<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Luciano Mammino</title><description>Cloud Architect and Fullstack Developer</description><link>https://loige.co/</link><item><title>Finally/First</title><link>https://loige.co/finally-first/</link><guid isPermaLink="true">https://loige.co/finally-first/</guid><description>A web developer fascinated by the web since childhood discusses the motivation behind starting a blog - to share thoughts on web development trends and experiments in a personal space.</description><pubDate>Thu, 16 Jan 2014 23:04:36 GMT</pubDate><content:encoded>&lt;p&gt;Yep! &lt;strong&gt;Finally&lt;/strong&gt; here’s the &lt;strong&gt;first&lt;/strong&gt; post on the path of this blog.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Finally/first&lt;/em&gt;, indeed a curious binomial with a weird sound, but I think it’s a good title to start this adventure.
I’ll try to keep it simple and avoid to bloat things out… just start dancing by answering to a simple question, maybe the proper one now: &lt;strong&gt;Why start a blog?&lt;/strong&gt;
Well, I’m a web developer, fascinated by the web since I was a child and started writing my first lines of code in &lt;em&gt;qbasic&lt;/em&gt;, and as any other serious web developer it happens to me to read tons of blogs to keep myself updated with the latest trends that pop out in this field. It also constantly happen to me to have the need to experiment something new in my free time. Summing it up I felt the need to build a space of mine in wich report my thoughts about web development and the result of some of these experiments.&lt;/p&gt;
&lt;p&gt;I think that’s all for now.
Stay tuned ;)&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/finally-first.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/finally-first.png" width="1200" height="630"/></media:content><category>life</category><author>Luciano Mammino</author><comments>https://loige.co/finally-first/#comments</comments><enclosure url="https://loige.co/og/finally-first.png" length="0" type="image/png"/></item><item><title>Symfony security: authentication made simple (well, maybe!)</title><link>https://loige.co/symfony-security-authentication-made-simple/</link><guid isPermaLink="true">https://loige.co/symfony-security-authentication-made-simple/</guid><description>This post collects resources and provides a graph to understand how Symfony authentication works behind the scenes, from the initial request to the final authenticated token. It clarifies the relationships between key classes like firewall, authentication provider and authentication listener.</description><pubDate>Fri, 14 Feb 2014 00:34:23 GMT</pubDate><content:encoded>&lt;p&gt;The &lt;a href=&quot;http://symfony.com/doc/current/components/security/introduction.html&quot;&gt;Symfony2 security component&lt;/a&gt; has the fame of being one of the most complex in the framework. I tend to believe that’s partially true, not because the component is really that complex, but because there are (really) a lot of concepts involved and it may be difficult to understand them all at once and have a clear vision as a whole.&lt;/p&gt;
&lt;p&gt;I am in the process of writing an &lt;a href=&quot;https://github.com/Oryzone/OryzoneOauthBundle&quot;&gt;OAuth bundle&lt;/a&gt; and I faced the need to deeply understand how the authentication process work in Symfony2 to being able to integrate the OAuth protocol with the Symfony authentication component.
Notice that I know there are a lot of great and stable OAuth bundles out there (have a look at the great &lt;a href=&quot;https://github.com/hwi/HWIOAuthBundle&quot;&gt;HWIOAuthBundle&lt;/a&gt; to which I had chance to submit small contributions in the past). My intention is not to build a better one, but I want to build my own bundle with some peculiar features and use it as a way to experiment and learn new things. But I am getting off topic!&lt;/p&gt;
&lt;p&gt;Going back to the Symfony2 security component, the point is that I found out difficult at first glance to get a clear idea of what is going on behind the scenes and what I need to write to create a custom authentication mechanism.&lt;/p&gt;
&lt;p&gt;So in this post I will try to collect few interesting resources that helped me understanding it better and a &lt;a href=&quot;#symfony-authentication-graph&quot;&gt;graph&lt;/a&gt; I drawn to resume what I learned.&lt;/p&gt;
&lt;h2 id=&quot;interesting-links&quot;&gt;Interesting links&lt;/h2&gt;
&lt;p&gt;I highly suggest you to read them in the proposed order.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://symfony.com/doc/current/components/security/introduction.html&quot;&gt;Symfony Security component documentation&lt;/a&gt;: must read! The official documentation about the security component. It covers both authentication and authorization. Be warned that it will probably not make things clear at first, but I believe you must start your learning from there!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.screenfony.com/blog/symfony-custom-authentication-provider&quot;&gt;Diving into security layer&lt;/a&gt;: a great blog post from &lt;a href=&quot;http://www.ftassi.com/&quot;&gt;Francesco Tassi&lt;/a&gt; of &lt;a href=&quot;http://www.screenfony.com/&quot;&gt;Screenfony&lt;/a&gt;. It carefully describes which classes and interfaces are involved in the authentication layer and how they are wired togheter. He does not present any example of code, but in my opinion this is one of the most interesting and clarifying post about this topic.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.slideshare.net/kriswallsmith/love-and-loss-a-symfony-security-play&quot;&gt;Love and Loss: A Symfony Security Play&lt;/a&gt;: slides by the great &lt;a href=&quot;http://kriswallsmith.net/&quot;&gt;Kris Wallsmith&lt;/a&gt; from the Symfony Live 2013 in Portland. Also a &lt;a href=&quot;http://kriswallsmith.net/post/56350579294/video-of-the-tech-talk-love-loss-a-symfony&quot;&gt;Video&lt;/a&gt; is available. That’s a great resource because Kris tries to explain with visual graphs how the various components are tied together and how the whole flow goes from request to response. Very clarifying!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://php-and-symfony.matthiasnoback.nl/2012/07/symfony2-introduction-to-the-security-component-part-i/&quot;&gt;Symfony2: Introduction to The Security Component Part I&lt;/a&gt;, &lt;a href=&quot;http://php-and-symfony.matthiasnoback.nl/2012/08/symfony2-introduction-to-the-security-component-part-ii/&quot;&gt;Part II&lt;/a&gt; &amp;#x26; &lt;a href=&quot;http://php-and-symfony.matthiasnoback.nl/2012/09/symfony2-introduction-to-the-security-component-part-iii/&quot;&gt;Part III&lt;/a&gt;: a series of articles by &lt;a href=&quot;http://php-and-symfony.matthiasnoback.nl/&quot;&gt;Matthias Noback&lt;/a&gt; that cover the various aspect of the Symfony security (both about authentication and authorization). They have been merged to the official documentation, so read it fast as a good way to recap ideas.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://symfony.com/video/1/security-in-real-life/English&quot;&gt;Security in real life&lt;/a&gt;: A video from the Symfony Live Paris 2012 by &lt;a href=&quot;http://jmsyst.com/blog/&quot;&gt;Johannes Schmitt&lt;/a&gt;. Johannes explains some common problems people face with the Symfony security component. He also provides a great introduction describing the most important classes and how they are tied together.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://symfony.com/doc/current/cookbook/security/custom_authentication_provider.html&quot;&gt;Custom authentication provider&lt;/a&gt;: a cookbook article from the official documentation that presents a code example on how to write a custom authentication provider to integrate the WSSE protocol in Symfony. Great code example!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://symfony.com/doc/current/cookbook/security/api_key_authentication.html&quot;&gt;How to Authenticate Users with API Keys&lt;/a&gt;: another great cookbook article that will shed some light on the topic by providing a simple example.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://symfony.com/doc/current/cookbook/security/custom_password_authenticator.html&quot;&gt;How to Create a Custom Form Password Authenticator&lt;/a&gt;: yet another interesting cookbook article with a code example on how to modify the authentication logic behind the form (username/password) based authenticator.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php&quot;&gt;Code of the RememberMe Listener&lt;/a&gt;: the code of the RememberMeListener class. A great and simple example on how to write a security authentication listener.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;symfony-authentication-graph&quot;&gt;Symfony Authentication graph&lt;/h2&gt;
&lt;p&gt;Notice that the following graph tries to represent the classical schema available in the Symfony Standard Edition. As the framework is extensible at any given point you are free to change the whole logic. The generic idea is that you start with a &lt;code&gt;Request&lt;/code&gt; object and you should check if it can be used to produce an &lt;code&gt;AuthenticatedToken&lt;/code&gt; according to some authentication logic.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.google.com/drawings/d/1uTA7gQZ5IEV51Nv-HKR98sKWQNBUhEm0PPueJcoRW7c/edit?usp=sharing&quot;&gt;&lt;img alt=&quot;Symfony Authentication chart&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;793&quot; height=&quot;1121&quot; src=&quot;https://loige.co/_astro/symfony_security_component_authentication_flow.7dPVxjML_Z1Dntve.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Get the image in &lt;a href=&quot;https://docs.google.com/drawings/d/1uTA7gQZ5IEV51Nv-HKR98sKWQNBUhEm0PPueJcoRW7c/edit?usp=sharing&quot;&gt;full resolution on Google Drive&lt;/a&gt; (you can also propose edits with comments if you want) or &lt;a href=&quot;/downloads/symfony_security_component_authentication_flow.pdf&quot;&gt;Download the PDF&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That’s all, I hope this post has been useful. If you have interesting link related to this topic feel free to add them in the comment box and I will add them into the article.&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/symfony-security-authentication-made-simple.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/symfony-security-authentication-made-simple.png" width="1200" height="630"/></media:content><category>php</category><category>symfony</category><category>security</category><author>Luciano Mammino</author><comments>https://loige.co/symfony-security-authentication-made-simple/#comments</comments><enclosure url="https://loige.co/og/symfony-security-authentication-made-simple.png" length="0" type="image/png"/></item><item><title>3 invitations to try Atom.io</title><link>https://loige.co/3-invitations-to-try-atom-io/</link><guid isPermaLink="true">https://loige.co/3-invitations-to-try-atom-io/</guid><description>The author received 3 invites to try Atom.io, a new text editor built by GitHub using Node.js. They find it promising but slower than SublimeText. The post shares the invites with readers who follow the author on social media and comment.</description><pubDate>Wed, 09 Apr 2014 10:58:22 GMT</pubDate><content:encoded>&lt;p&gt;I have finally got my invitation to try the new text editor &lt;a href=&quot;https://atom.io&quot;&gt;Atom.io&lt;/a&gt;. Atom is built with web technologies (node.js in it’s core) by the folks at GitHub and it’s somewhat very similar to the famous &lt;a href=&quot;http://www.sublimetext.com/&quot;&gt;SublimeText&lt;/a&gt;.
In my opinion it seems very promising (even if it’s significantly slower than SublimeText), anyway I have to try it a lot more before shaping a serious opinion about it.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Atom.io screenshoot&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1200&quot; height=&quot;734&quot; src=&quot;https://loige.co/_astro/Schermata-2014-04-09-alle-12-55-17.C1g--LG9_jnQxX.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;The point of this topic is that Atom.io is currently in closed beta and I have received 3 invitations to share with whom is willing to try it.&lt;/p&gt;
&lt;p&gt;I would be glad to &lt;strong&gt;share the invitations&lt;/strong&gt; with the first 3 readers who would &lt;strong&gt;follow me&lt;/strong&gt; on &lt;a href=&quot;https://github.com/lmammino&quot;&gt;GitHub&lt;/a&gt; or &lt;a href=&quot;https://twitter.com/loige&quot;&gt;Twitter&lt;/a&gt; &lt;strong&gt;and write a comment&lt;/strong&gt; on this post.&lt;/p&gt;
&lt;p&gt;PS: You would probably need a GitHub account!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;, April 12:
Sorry guys, my invitations have gone for now.
Anyway it seems that GitHub distributes other invitations sometime. So if you haven’t been in time you can still write a comment and if I ever manage to have other invites i will follow the order of the order to share them with you.&lt;/p&gt;
&lt;p&gt;Hope you will enjoy it.&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/3-invitations-to-try-atom-io.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/3-invitations-to-try-atom-io.png" width="1200" height="630"/></media:content><category>atom-io</category><author>Luciano Mammino</author><comments>https://loige.co/3-invitations-to-try-atom-io/#comments</comments><enclosure url="https://loige.co/og/3-invitations-to-try-atom-io.png" length="0" type="image/png"/></item><item><title>Introducing ORM Cheatsheet</title><link>https://loige.co/introducing-orm-cheatsheet/</link><guid isPermaLink="true">https://loige.co/introducing-orm-cheatsheet/</guid><description>ORM Cheatsheet is a useful website that serves as a quick reference guide for developers struggling to remember how to use common PHP ORM libraries like Doctrine 2 and Propel. It provides examples for annotations, relationships, and configuration.</description><pubDate>Fri, 11 Apr 2014 08:50:53 GMT</pubDate><content:encoded>&lt;p&gt;This week I received an interesting email from Martin Stradej, the developer of &lt;a href=&quot;http://www.orm-designer.com&quot;&gt;ORM Designer&lt;/a&gt;, a tool to design ORM relationships with a simple but powerful graphic user interface.&lt;/p&gt;
&lt;p&gt;Martin wrote the mail because he wanted to acknowledge me of his latest project: &lt;a href=&quot;http://ormcheatsheet.com&quot;&gt;ORM Cheatsheet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://ormcheatsheet.com&quot;&gt;&lt;img alt=&quot;ORM Cheatsheet homepage screenshoot&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1052&quot; height=&quot;893&quot; src=&quot;https://loige.co/_astro/orm-cheatsheet-screenshoot.DDwUYKht_Z2p1QuW.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ORM Cheatsheet, as the name suggests, is nothing more than a reference website for those who struggles with some of the most common Php ORM libraries (it currently supports &lt;em&gt;Doctrine2&lt;/em&gt; and &lt;em&gt;Doctrine&lt;/em&gt;, but it seems that &lt;em&gt;Propel&lt;/em&gt; and &lt;em&gt;Cake PHP&lt;/em&gt; will be supported too).&lt;/p&gt;
&lt;p&gt;In my honest opinion, the great thing about the website is that it is a really useful resource if you always spend a lot of time searching the official Doctrine reference to check how the hell a given annotation is supposed to work or how to create a particular kind of relationship. If you are already confident with Doctrine and just can’t remember how to set up something it is the perfect place to go to freshen up your memory.&lt;/p&gt;
&lt;p&gt;It also guides you on how to configure the Doctrine library to work with a standalone PHP project or even with a &lt;em&gt;Symfony&lt;/em&gt; (both version 2 and 1.4) or a &lt;em&gt;Zend Framework 2&lt;/em&gt; based one.&lt;/p&gt;
&lt;p&gt;The project has its own &lt;a href=&quot;https://github.com/atlantic18/ormcheatsheet&quot;&gt;GitHub repository&lt;/a&gt; so everyone can submit a pull request and improve the project.&lt;/p&gt;
&lt;p&gt;That’s all&lt;/p&gt;
&lt;p&gt;Have a nice weekend&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/introducing-orm-cheatsheet.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/introducing-orm-cheatsheet.png" width="1200" height="630"/></media:content><category>php</category><category>doctrine</category><category>orm</category><author>Luciano Mammino</author><comments>https://loige.co/introducing-orm-cheatsheet/#comments</comments><enclosure url="https://loige.co/og/introducing-orm-cheatsheet.png" length="0" type="image/png"/></item><item><title>5 lessons learned at the Bank of Ireland Accelerator</title><link>https://loige.co/5-lessons-learned-at-the-bank-of-ireland-accelerator/</link><guid isPermaLink="true">https://loige.co/5-lessons-learned-at-the-bank-of-ireland-accelerator/</guid><description>The author shares 5 powerful quotes and lessons learned from mentors during an intensive 3-month accelerator program in Ireland focused on startups and entrepreneurship. Key takeaways include the importance of passion, understanding customers&apos; problems, building a great team, and working tirelessly while maintaining positivity.</description><pubDate>Mon, 22 Dec 2014 21:23:58 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;What a hell of 3 months!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;During the last 3 months I haven’t got a single minute to take care of this blog. I started a new adventure and moved to Ireland to attend the Bank of Ireland Accelerator Programme in Cork with my startup &lt;a href=&quot;http://sbaam.com&quot;&gt;Sbaam&lt;/a&gt;. There I spent 3 incredible months with a huge amount of lessons learned about &lt;strong&gt;startups&lt;/strong&gt; and &lt;strong&gt;entrepreneurship&lt;/strong&gt;. I want to share with you 5 of the best quotes I heard from the mentors and explain what I learned from them.&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Consider this is my first “non technical” post with a lot of english written text. You’ll probalby find it plenty of mistakes, so feel free to &lt;a href=&quot;mailto:loige@hotmail.com&quot;&gt;send me an email&lt;/a&gt; and help me to improve it (and improve my english too :P)&lt;/small&gt;&lt;/p&gt;
&lt;h2 id=&quot;being-an-entrepreneur-is-hell&quot;&gt;Being an entrepreneur is hell&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;“Welcome… to hell!”&lt;/p&gt;
&lt;p&gt;– Bill Liao (&lt;a href=&quot;https://twitter.com/liaonet&quot; title=&quot;follow Bill on Twitter&quot;&gt;@liaonet&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the very first phrase I remember from a mentor. It was the opening day and Bill was one of the first speakers. He wanted to warn us about the upcoming months, but also about our choice of being entrepreneurs.&lt;/p&gt;
&lt;p&gt;Yes, it may sound trivial but it’s true. Many think that being an entrepreneur means freedom, money and 0 responsibilities. The truth is that this is absolutely not the case!&lt;/p&gt;
&lt;p&gt;Entrepreneurs work a lot more than the usual workers (and this very often includes nights, weekends and holidays). They have to care about their business in every single moment and every stakeholder ends up to be their boss: customers, investors and partners require a lot of attention, their money (and time) are not supposed to be wasted!&lt;/p&gt;
&lt;p&gt;And, speaking about entrepreneurs’ earning, get ready to spend months, sometimes even years, without a single cent in your pocket especially if it’s your first time as an entrepreneur. Every penny you have should be invested in your business because at the end of the day &lt;strong&gt;you are the “number one” investor of your company&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;understand-who-you-are-what-you-want-to-accomplish-but-dont-forget-about-your-customers&quot;&gt;Understand who you are, what you want to accomplish but don’t forget about your customers&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;“Nail it and then scale it! Find your first 100 happy customers and really understand them”&lt;/p&gt;
&lt;p&gt;– Sean O’Sullivan (&lt;a href=&quot;https://twitter.com/sosventures&quot; title=&quot;follow Sean on Twitter&quot;&gt;@sosventures&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sean explained us why most of the businesses fail: they simply are not focused in trying to solve a problem for their customers!
It’s crucial to understand what you are doing and what your customers need. You shouldn’t really keep adding 10 thousand features to your product or trying to attack every possible market and regions from day one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Start small&lt;/strong&gt;. Find a niche and try to grasp what’s the real pain there. Then see if your solution solves the problem for real and see if people are willing to pay for it. If that’s the case you found your first customers, well done! They are your most valuable asset, so you have to be sure they are really happy with you and that your solution is the best for them before trying to move on to a broader audience.&lt;/p&gt;
&lt;h2 id=&quot;passion-breaks-the-point&quot;&gt;Passion breaks the point!&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;“You need to be totally and utterly in love with your business as it keeps you alive and your business itself alive”&lt;/p&gt;
&lt;p&gt;– Daniel Ramamoorthy (&lt;a href=&quot;https://twitter.com/mynameisdanram&quot; title=&quot;follow Daniel on Twitter&quot;&gt;@mynameisdanram&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Daniel has an incredible attitude of life and he is a surprisingly positive person. This quality is not something he is born with, but something that he developed in time and something that everyone can develop.&lt;/p&gt;
&lt;p&gt;Great success can be achieved only if you work hard on staying positive and if you are totally passionate about what you are doing.
You will spend so much time and energies on your business that you can really perform only if this motivates you and makes you feel good.&lt;/p&gt;
&lt;p&gt;There will be times when everything will go wrong and it will be almost impossible to remain positive. These are the moments in which you should find your way to keep going and recover your positivity. Going out for a walk, practicing some sport, reading a book, watching a movie, listen to your favourite music, talking with a friend are just few of the thousand possible solutions. Everyone is different and the key here is to find out what’s the best way for you to release the stress and be ready to start again.&lt;/p&gt;
&lt;p&gt;Daniel told us that he printed his favourite quote on the ceiling over his bed. Everytime he wakes up in the morning this is the first thing he see and this allows him to remember who he is and what he is passionate about, this makes him ready to do his best during the day.&lt;/p&gt;
&lt;h2 id=&quot;surround-yourself-with-great-people&quot;&gt;Surround yourself with great people&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;“You are the average of the five people you spend most time with”&lt;/p&gt;
&lt;p&gt;– Seàn Gallagher (&lt;a href=&quot;https://twitter.com/seangallagher1&quot; title=&quot;follow Seàn on Twitter&quot;&gt;@seangallagher1&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Nobody is alone. Unless you are an hermit in the Himalayas your days will be spent with different people from work to family and friends.
The fact is that every one can give you something, so the trick is to surround yourself with the best people you can find. People that can teach you how to be better at something, people that can make you feel positive, people that can transmit their experience to you, people that can compensate your weaknesses. If you can do this you will surely became a better person day by day and will live happier.&lt;/p&gt;
&lt;p&gt;This obviously applies also to your business: &lt;strong&gt;team, team, team&lt;/strong&gt;! If you are an entrepreneur you will spend most of your days with your team so you have to build the best team in the whole World. Not necessarily the best in terms of individual skills but the best in terms of people and the synergy with them.&lt;/p&gt;
&lt;p&gt;Just imagine what can happen to your business if your core team is not the right one…&lt;/p&gt;
&lt;h2 id=&quot;you-should-work-really-hard-if-you-want-to-look-as-good-as-a-swan&quot;&gt;You should work really hard if you want to look as good as a swan!&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;“You need to be as smooth as a graceful swan on a lake but you must keep pedalling very hard under the surface to maintain that forward momentum”&lt;/p&gt;
&lt;p&gt;– Wayne Murphy, programme manager (&lt;a href=&quot;https://twitter.com/waynemurphy77&quot; title=&quot;follow Wayne on Twitter&quot;&gt;@waynemurphy77&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is really a great metaphor. I simply loved it.
I have two different interpretation of it.&lt;/p&gt;
&lt;p&gt;The first is that you have to look great to every external observer, almost pretending that everything is possible for you. But being able to do so requires a huge and continuous effort, you can’t fake it, you have to earn it!&lt;/p&gt;
&lt;p&gt;My second interpretation is that once you start having some traction and you are floating smoothly on your way you have to start working even harder to keep the momentum and reach the next great milestone. So don’t make the mistake to relax at the first goal reached, but immediately look at the next one and do what’s needed to reach it, immediately!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;These three months have been probably the best of my life in terms of learning and experience, so &lt;strong&gt;I have to say a huge “thank you” to everyone that made this possible&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Secondly i’d like to have your opinion and interpretation of all this quotes. Feel free to &lt;strong&gt;leave a comment and tell me which one of these five lessons you liked most&lt;/strong&gt;.&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/5-lessons-learned-at-the-bank-of-ireland-accelerator.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/5-lessons-learned-at-the-bank-of-ireland-accelerator.png" width="1200" height="630"/></media:content><category>startup</category><category>entrepreneurship</category><author>Luciano Mammino</author><comments>https://loige.co/5-lessons-learned-at-the-bank-of-ireland-accelerator/#comments</comments><enclosure url="https://loige.co/og/5-lessons-learned-at-the-bank-of-ireland-accelerator.png" length="0" type="image/png"/></item><item><title>New PHP library: PHPoAuthUserData</title><link>https://loige.co/new-php-library-php-oauth-user-data/</link><guid isPermaLink="true">https://loige.co/new-php-library-php-oauth-user-data/</guid><description>The PHPoAuthUserData library provides a simple interface to extract common user data like name, username, ID from various OAuth providers. It builds on top of PHPoAuthLib.</description><pubDate>Mon, 10 Feb 2014 12:13:50 GMT</pubDate><content:encoded>&lt;p&gt;I recently wrote a new &lt;a href=&quot;https://github.com/Oryzone/PHPoAuthUserData&quot;&gt;PHP library&lt;/a&gt; to simplify the extraction of user data (&lt;em&gt;name&lt;/em&gt;, &lt;em&gt;email&lt;/em&gt;, &lt;em&gt;id&lt;/em&gt;, etc…) from various OAuth providers such as &lt;em&gt;Facebook&lt;/em&gt;, &lt;em&gt;Twitter&lt;/em&gt; and &lt;em&gt;Linkedin&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Is well know that OAuth 1 and 2 are great &lt;em&gt;standard&lt;/em&gt; protocols to authenticate users in our apps. Anyway we often need to go further the authentication process and extract various information about the authenticated users. Unfortunately this is something that is not standardized and obviously each OAuth provider manages user data in very specific manner according to its specific purposes.&lt;/p&gt;
&lt;p&gt;So each OAuth provider offer a set of APIs with specific data schemes to allow developers to extract data about the authenticated users.&lt;/p&gt;
&lt;p&gt;That’s not a big deal if we build apps that adopts a single OAuth provider, but, if we want to adopt more of them, you need to deal with several different APIs and data schemes! Yes, things can get really cumbersome!&lt;/p&gt;
&lt;p&gt;Just to make things clearer suppose you want to allow users in your app to sign up with Facebook, Twitter and Linkedin. Probably, to increase conversion rate and speed up the sign up process, you may want to populate the user profile on your app by copying data from the OAuth provider user profile he used to sign up. Yes, you have to deal with 3 different sets of APIs and data schemes! And suppose you would be able to add GitHub and Google one day, that will count for 5 different APIs and data schemes… not so maintainable, isn’t it?&lt;/p&gt;
&lt;p&gt;The library I wrote is called &lt;a href=&quot;https://github.com/Oryzone/PHPoAuthUserData&quot;&gt;PHPoAuthUserData&lt;/a&gt;. It sits on top of the excellent OAuth library &lt;a href=&quot;https://github.com/Lusitanian/PHPoAuthLib&quot;&gt;Lusitanian/PHPoAuthLib&lt;/a&gt; and aims to resolve the user extraction data problem in the most simple and effective way.&lt;/p&gt;
&lt;p&gt;It offers a &lt;em&gt;uniform&lt;/em&gt; and (really) simple interface to extract the most interesting and common user data such as &lt;em&gt;Name&lt;/em&gt;, &lt;em&gt;Username&lt;/em&gt;, &lt;em&gt;Id&lt;/em&gt; and so on.&lt;/p&gt;
&lt;p&gt;Just to give you a &lt;em&gt;quick&lt;/em&gt; idea of what is possible with the library have a look at the following snippet:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// $service is an istance of \OAuth\Common\Service\ServiceInterface (eg. the &quot;Facebook&quot; service) with a valid access token&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$extractorFactory&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; \OAuth\UserData\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;ExtractorFactory&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$extractor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$extractorFactory&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$service&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// get the extractor for the given service&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$extractor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getUniqueId&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// prints out the unique id of the user&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$extractor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getUsername&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// prints out the username of the user&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$extractor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getImageUrl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// prints out the url of the user profile image&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// $service is an istance of \OAuth\Common\Service\ServiceInterface (eg. the &amp;#x22;Facebook&amp;#x22; service) with a valid access token$extractorFactory = new \OAuth\UserData\ExtractorFactory();$extractor = $extractorFactory-&gt;get($service); // get the extractor for the given serviceecho $extractor-&gt;getUniqueId(); // prints out the unique id of the userecho $extractor-&gt;getUsername(); // prints out the username of the userecho $extractor-&gt;getImageUrl(); // prints out the url of the user profile image&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The code is available on &lt;a href=&quot;https://github.com/Oryzone/PHPoAuthUserData&quot;&gt;Github&lt;/a&gt; where you will find detailed information on how to install and use the library.&lt;/p&gt;
&lt;p&gt;I Hope you will enjoy it and be willing to contribute to the code base. If you want to know more, read the next post that explains &lt;a href=&quot;http://loige.com/writing-a-new-extractor-for-php-oauth-user-data/&quot;&gt;how to write an extractor for the library&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/new-php-library-php-oauth-user-data.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/new-php-library-php-oauth-user-data.png" width="1200" height="630"/></media:content><category>library</category><category>php</category><category>oauth</category><category>github</category><author>Luciano Mammino</author><comments>https://loige.co/new-php-library-php-oauth-user-data/#comments</comments><enclosure url="https://loige.co/og/new-php-library-php-oauth-user-data.png" length="0" type="image/png"/></item><item><title>Integrating Twig.js and BazingaJsTranslationBundle</title><link>https://loige.co/integrating-twig-js-and-bazingajstranslationbundle/</link><guid isPermaLink="true">https://loige.co/integrating-twig-js-and-bazingajstranslationbundle/</guid><description>The post explains how to integrate twig.js with BazingaJsTranslationBundle to handle translations consistently between PHP and JavaScript. It shows how to build a custom Twig extension to translate strings with the Bazinga Translator object and handle differences in parameter formatting.</description><pubDate>Fri, 28 Feb 2014 11:40:05 GMT</pubDate><content:encoded>&lt;p&gt;Recently I had the need to run a twig template that uses the &lt;code&gt;trans&lt;/code&gt; filter on my frontend using &lt;a href=&quot;http://jmsyst.com/libs/twig.js&quot;&gt;twig.js&lt;/a&gt;, a pure JavaScript port of twig written by the good &lt;a href=&quot;http://jmsyst.com/&quot;&gt;Johannes Schmitt&lt;/a&gt;.
The JavaScript version does not handle all the functionalities offered by the original PHP version (even if it goes pretty close) and in particular it does not natively handle the &lt;code&gt;trans&lt;/code&gt; filter.&lt;/p&gt;
&lt;p&gt;So, at first, I got a JavaScript runtime exception on my page when trying to use the template.
Luckily enough the JavaScript version of twig is extensible like the PHP one and it is very easy to add new filters and functions.&lt;/p&gt;
&lt;p&gt;In my specific case I had a Symfony application where I was already using &lt;a href=&quot;https://github.com/willdurand/BazingaJsTranslationBundle&quot;&gt;BazingaJsTranslationBundle&lt;/a&gt; to manage dynamic translations on the frontend. As I discovered the twig.js extensibility, it was very easy to start building a twig.js extension by using the &lt;code&gt;Translator&lt;/code&gt; JavaScript object offered by the Bazinga bundle.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: I will not go into the details about how to install twig.js and BazingaJsTranslationBundle in a Symfony application. You can find all the needed informations on their websites/github pages.&lt;/p&gt;
&lt;p&gt;In my first attempt I wrote something like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Twig&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;setFilter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;trans&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;domain&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;locale&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Translator&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;trans&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;domain&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;locale&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Twig.setFilter(&amp;#x27;trans&amp;#x27;, function(id, params, domain, locale) {  return Translator.trans(id, params, domain, locale)})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That seemed to work pretty good until I started to use translation strings with parameters. Parameters were not replaced with their respective values!
The problem laid in a subtle differece on how the BazingaJsTranslationBundle and the standard twig handle parameters. Let’s see a simple example.&lt;/p&gt;
&lt;p&gt;Suppose we have the string &lt;code&gt;hello %name%&lt;/code&gt;. With twig we expect to do something like:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{{ &apos;hello %name%&apos;|trans({ &apos;%name%&apos; : &apos;Alice&apos; }) }}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{{ &amp;#x27;hello %name%&amp;#x27;|trans({ &amp;#x27;%name%&amp;#x27; : &amp;#x27;Alice&amp;#x27; }) }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note the &lt;code&gt;%&lt;/code&gt; delimiters around the parameter name.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Translator.trans&lt;/code&gt; method expects an hash map without parameter delimiters in it. So we would have to do something like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Translator&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;trans&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;hello %name%&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, { &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;name&apos;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; ; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Alice&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; });&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Translator.trans(&amp;#x22;hello %name%&amp;#x22;, { &amp;#x27;name&amp;#x27; ; &amp;#x27;Alice&amp;#x27; });&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note that there’s no &lt;code&gt;%&lt;/code&gt; delimiter this time.
The &lt;code&gt;Translator.trans&lt;/code&gt; method manages the detection of parameters by itself and you can also decide to customize the delimiters by setting the values: &lt;code&gt;Translator.placeHolderPrefix&lt;/code&gt; and &lt;code&gt;Translator.placeHolderSuffix&lt;/code&gt;.
Obviously I suggest you to be consistent and use the same placeholders you use with PHP (especially if you need to share templates and translations from the backend to the frontend).&lt;/p&gt;
&lt;p&gt;So my final solution was the following:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Twig&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;setFilter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;trans&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;domain&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;locale&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// normalizes params (removes placeholder prefixes and suffixes)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;hasOwnProperty&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Translator&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;placeHolderPrefix&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Translator&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;placeHolderSuffix&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;substr&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#016C9A&quot;&gt;delete&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Translator&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;trans&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;domain&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;locale&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Twig.setFilter(&amp;#x27;trans&amp;#x27;, function(id, params, domain, locale) {  params = params || {}  // normalizes params (removes placeholder prefixes and suffixes)  for (var key in params) {    if (      params.hasOwnProperty(key) &amp;#x26;&amp;#x26;      key[0] == Translator.placeHolderPrefix &amp;#x26;&amp;#x26;      key[key.length - 1] == Translator.placeHolderSuffix    ) {      params[key.substr(1, key.length - 2)] = params[key]      delete params[key]    }  }  return Translator.trans(id, params, domain, locale)})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This way it automatically normalizes parameters for the &lt;code&gt;Translator&lt;/code&gt; object (by removing any delimiter from parameter keys) and I have a consistent behavior between twig and twig.js.
My normalization approach is very rough and you can surely find a better approach (maybe using a regex).
Let me know if you do it ;)&lt;/p&gt;
&lt;p&gt;Obviously you can also avoid the normalization and keep the responsibility to pass the parameters hash map in the way the &lt;code&gt;Translator&lt;/code&gt; object expects it (without delimiters). In this case you can stick to my first implementation.&lt;/p&gt;
&lt;p&gt;That’s all. See ya ;)&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/integrating-twig-js-and-bazingajstranslationbundle.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/integrating-twig-js-and-bazingajstranslationbundle.png" width="1200" height="630"/></media:content><category>php</category><category>symfony</category><category>javascript</category><category>translation</category><category>twig</category><author>Luciano Mammino</author><comments>https://loige.co/integrating-twig-js-and-bazingajstranslationbundle/#comments</comments><enclosure url="https://loige.co/og/integrating-twig-js-and-bazingajstranslationbundle.png" length="0" type="image/png"/></item><item><title>Transparent pixel response with Symfony, how to track email opening</title><link>https://loige.co/transparent-pixel-response-with-symfony-how-to-track-email-opening/</link><guid isPermaLink="true">https://loige.co/transparent-pixel-response-with-symfony-how-to-track-email-opening/</guid><description>This blog post explains how to implement email open tracking in Symfony using a transparent tracking pixel. It provides code examples for generating a tracking image response and handling the tracking logic in a controller.</description><pubDate>Fri, 13 Jun 2014 10:33:04 GMT</pubDate><content:encoded>&lt;p&gt;If you have ever heard about “&lt;strong&gt;transparent pixel&lt;/strong&gt;”, “&lt;strong&gt;1x1 blank pixel&lt;/strong&gt;”, “&lt;strong&gt;tracking pixel&lt;/strong&gt;” or simply “&lt;strong&gt;tracking image&lt;/strong&gt;” you probably know what we are going to talk about and can just &lt;a href=&quot;#symfonyimplementation&quot;&gt;skip to the implementation&lt;/a&gt;!&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Transparent pixel image is a technique often used to track some user behavior (often visits or views to a certain online content) in scenarios where you can’t use javascript.&lt;/p&gt;
&lt;p&gt;One of the most common scenarios is probably email opening tracking. Can you put Google Analytics into an email? Well, probably it would not work as expected… So there’s something we can do? Of course there is, let’s jump into a concrete example.&lt;/p&gt;
&lt;h2 id=&quot;track-email-opening&quot;&gt;Track email opening&lt;/h2&gt;
&lt;p&gt;The following image shows the typical tracking flow applied to emails:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Tracking email opening&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;900&quot; height=&quot;524&quot; src=&quot;https://loige.co/_astro/email-tracking.oo8jZk9__Z27R5Ir.webp&quot; &gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;A user receives our HTML email. Within the email content there’s a “smart” tracking image: &lt;code&gt;&amp;#x3C;img src=&quot;http://example.com/track.gif?id=1234&quot;&gt;&lt;/code&gt;. Notice that it points to our server &lt;strong&gt;example.com&lt;/strong&gt; and has a parameter &lt;code&gt;id=1234&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When the user opens the email, his email client will start to download all the resources linked into the HTML code (usually images) and it will trigger a request to download the tracking image.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The request is handled by the &lt;strong&gt;example.com&lt;/strong&gt; webserver. It does not handle the request as a static image but it executes some logic. It checks the &lt;code&gt;id&lt;/code&gt; parameter and uses it to determine which email has triggered the request. Then it marks that email as opened in its own database for future reports. The mail client is still waiting for an answer and it expects an image. So the webserver generates on the fly the most small image possible: a 1x1 transparent image!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then the image is sent back to the client that will render it on the screen. Anyway the image is trasparent and so small that the user will barely notice it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;symfony-implementation&quot;&gt;Symfony implementation&lt;/h2&gt;
&lt;p&gt;Now let’s see how to implement this tracking flow using the Symfony framework.&lt;/p&gt;
&lt;p&gt;Notice that you should have your own logic to generate emails, to store and send them. I will not cover these parts, but only the one related to the tracking flow explained before.&lt;/p&gt;
&lt;p&gt;First of all, we want to have a dedicated &lt;code&gt;Response&lt;/code&gt; class to send back a transparent pixel to the client, let’s call it &lt;code&gt;TransparentPixelResponse&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;php&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;LMammino\Http&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Symfony\Component\HttpFoundation\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* Class TransparentPixelResponse&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;@package&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; LMammino\Http&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;@author&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; Luciano Mammino &amp;#x3C;lucianomammino@gmail.com&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;TransparentPixelResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Response&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* Base 64 encoded contents for 1px transparent gif and png&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;@var&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;string&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;IMAGE_CONTENT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; =&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;R0lGODlhAQABAJAAAP8AAAAAACH5BAUQAAAALAAAAAABAAEAAAICBAEAOw==&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* The response content type&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;@var&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;string&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;CONTENT_TYPE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;image/gif&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* Constructor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;__construct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$content&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;base64_decode&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;IMAGE_CONTENT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;parent&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;__construct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$content&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;headers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Content-Type&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;CONTENT_TYPE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;setPrivate&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;headers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;addCacheControlDirective&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;no-cache&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;headers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;addCacheControlDirective&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;must-revalidate&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;?phpnamespace LMammino\Http;use Symfony\Component\HttpFoundation\Response;/** * Class TransparentPixelResponse * @package LMammino\Http * @author Luciano Mammino &lt;lucianomammino@gmail.com&gt; */class TransparentPixelResponse extends Response{    /**     * Base 64 encoded contents for 1px transparent gif and png     * @var string     */    const IMAGE_CONTENT =        &amp;#x27;R0lGODlhAQABAJAAAP8AAAAAACH5BAUQAAAALAAAAAABAAEAAAICBAEAOw==&amp;#x27;    ;    /**     * The response content type     * @var string     */    const CONTENT_TYPE = &amp;#x27;image/gif&amp;#x27;;    /**     * Constructor     */    public function __construct()    {        $content = base64_decode(self::IMAGE_CONTENT);        parent::__construct($content);        $this-&gt;headers-&gt;set(&amp;#x27;Content-Type&amp;#x27;, self::CONTENT_TYPE);        $this-&gt;setPrivate();        $this-&gt;headers-&gt;addCacheControlDirective(&amp;#x27;no-cache&amp;#x27;, true);        $this-&gt;headers-&gt;addCacheControlDirective(&amp;#x27;must-revalidate&amp;#x27;, true);    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The logic is very simple here. We have hardcoded the content of a 1x1 transparent gif image using a base64 encoded string.
We use this string to set the content of the response object. We also set some cache headers to mark the response as not cacheable.&lt;/p&gt;
&lt;p&gt;Now we can write a controller that will handle the tracking request:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;php&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Symfony\Bundle\FrameworkBundle\Controller\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Controller&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Symfony\Component\HttpFoundation\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Request&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Sensio\Bundle\FrameworkExtraBundle\Configuration\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Route&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; LMammino\Http\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;TransparentPixelResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;TrackingController&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Controller&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* @Route(&apos;/track.gif&apos;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;trackEmailAction&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Request&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$request&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$request&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; !== &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//... executes some logic to retrieve the email and mark it as opened&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;TransparentPixelResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;?phpuse Symfony\Bundle\FrameworkBundle\Controller\Controller;use Symfony\Component\HttpFoundation\Request;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use LMammino\Http\TransparentPixelResponse;class TrackingController extends Controller{  /**     * @Route(&amp;#x27;/track.gif&amp;#x27;)     */    public function trackEmailAction(Request $request)    {      $id = $request-&gt;query-&gt;get(&amp;#x27;id&amp;#x27;);        if (null !== $id) {            //... executes some logic to retrieve the email and mark it as opened        }        return new TransparentPixelResponse();    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Here the logic is pretty simple too.
We created a controller with a &lt;code&gt;trackEmail&lt;/code&gt; action. The action has been assigned to the route &lt;code&gt;/track.gif&lt;/code&gt; using the &lt;code&gt;Route&lt;/code&gt; annotation (if you prefer you can do it also by using the yaml or the xml convention).
Within this action we just read the parameter &lt;code&gt;id&lt;/code&gt; from the request and used it to execute the persistence logic to retrive the email record and mark it as opened (skipped in the example).
Then we just have to return a new instance of our &lt;code&gt;TransparentPixelResponse&lt;/code&gt; class.&lt;/p&gt;
&lt;p&gt;That’s it! Pretty simple, isn’t it?&lt;/p&gt;
&lt;p&gt;###Improve performance&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE 2014-06-16&lt;/strong&gt;: A comment from &lt;a href=&quot;http://disqus.com/Lumbendil&quot;&gt;Lumbendil&lt;/a&gt; pointed out that it would be possible to do the “heavy logic” within a &lt;code&gt;kernel.terminate&lt;/code&gt; event listener. So let’s refactor our code to follow this good suggestion:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;php&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Symfony\Bundle\FrameworkBundle\Controller\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Controller&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Symfony\Component\HttpKernel\Event\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;KernelEvent&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Symfony\Component\HttpKernel\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;KernelEvents&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Symfony\Component\HttpFoundation\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Request&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Sensio\Bundle\FrameworkExtraBundle\Configuration\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Route&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; LMammino\Http\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;TransparentPixelResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;TrackingController&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Controller&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* @Route(&apos;/track.gif&apos;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;trackEmailAction&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Request&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$request&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$request&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; !== &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$dispatcher&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;event_dispatcher&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$dispatcher&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;addListener&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;KernelEvents&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;TERMINATE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;KernelEvent&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$event&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;){&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                   &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//... executes some logic to retrieve&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                   &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// the email and mark it as opened&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;TransparentPixelResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;?phpuse Symfony\Bundle\FrameworkBundle\Controller\Controller;use Symfony\Component\HttpKernel\Event\KernelEvent;use Symfony\Component\HttpKernel\KernelEvents;use Symfony\Component\HttpFoundation\Request;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use LMammino\Http\TransparentPixelResponse;class TrackingController extends Controller{  /**     * @Route(&amp;#x27;/track.gif&amp;#x27;)     */    public function trackEmailAction(Request $request)    {      $id = $request-&gt;query-&gt;get(&amp;#x27;id&amp;#x27;);        if (null !== $id) {          $dispatcher = $this-&gt;get(&amp;#x27;event_dispatcher&amp;#x27;);            $dispatcher-&gt;addListener(KernelEvents::TERMINATE,                function(KernelEvent $event) use ($id){                   //... executes some logic to retrieve                   // the email and mark it as opened                }            );        }        return new TransparentPixelResponse();    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Notice that we have “wrapped” our potentially heavy logic within a callable function that gets executed when the &lt;a href=&quot;http://symfony.com/doc/current/components/http_kernel/introduction.html#component-http-kernel-kernel-terminate&quot;&gt;&lt;code&gt;kernel.terminate&lt;/code&gt;&lt;/a&gt; event is fired. This way the response is returned immediatly (before executing all the heavy logic) and the requesting client will not have to wait for processing.&lt;/p&gt;
&lt;p&gt;Obviously, from the point of view of the server, we are not “really” improving performance. The code is not executed faster, but only in a different order. There’s only an apparent performance improvement for the web client who receives the response quicker and doesn’t care about the processing logic that will keep running on the server side.&lt;/p&gt;
&lt;p&gt;Keep in mind that the &lt;code&gt;kernel.terminate&lt;/code&gt; event is optional, and should only be called if your kernel implements &lt;code&gt;TerminableInterface&lt;/code&gt; (it should work if you are using the Symfony Standard Edition).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://disqus.com/Lumbendil&quot;&gt;Lumbendil&lt;/a&gt; also pointed out that this solution is not the only one possible. You can also rely on some messaging/queue system such as &lt;a href=&quot;http://www.rabbitmq.com&quot;&gt;RabbitMq&lt;/a&gt;, &lt;a href=&quot;http://gearman.org&quot;&gt;Gearman&lt;/a&gt; or &lt;a href=&quot;http://kr.github.io/beanstalkd&quot;&gt;Beanstalkd&lt;/a&gt;. These are great tools but they add new dependencies and a whole new layer of complexity to the web infrastructure, so I will suggest to use one of them only if your logic is very complex or heavy (or if you are designing you whole infrastructure from scratch to leverage a work queue system).&lt;/p&gt;
&lt;h2 id=&quot;considerations&quot;&gt;Considerations&lt;/h2&gt;
&lt;p&gt;You can apply this method to track email opening or views on other online contents such as Html webpages (in cases where you can’t or don’t want to use javascript).
Anyway, regarding tracking email opening, you should be aware that &lt;strong&gt;some e-mail clients block images loading&lt;/strong&gt; when you open an e-mail from an unknown sender. Yes, they do it not only to save your bandwidth, but mostly to avoid triggering tracking images! So in this cases you will not able to track the email opening, unless the user authorizes its client to load all the images in that specific email.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE 2014-06-17&lt;/strong&gt;: &lt;a href=&quot;http://disqus.com/jeltesteijaert/&quot;&gt;Jelte Steijaert&lt;/a&gt; reported that using email authentication systems such as &lt;a href=&quot;http://www.dkim.org/&quot;&gt;DKIM&lt;/a&gt; or &lt;a href=&quot;http://www.openspf.org/&quot;&gt;SPF&lt;/a&gt; will increase chances for images to get autoloaded by email clients. This authentication methods are also very useful to save your emails from ending up into the spam folder, so they are very recommended!&lt;/p&gt;
&lt;p&gt;If you have some other consideration you are very welcome to write a comment, as always!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/transparent-pixel-response-with-symfony-how-to-track-email-opening.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/transparent-pixel-response-with-symfony-how-to-track-email-opening.png" width="1200" height="630"/></media:content><category>php</category><category>symfony</category><category>http</category><category>tracking</category><category>email</category><author>Luciano Mammino</author><comments>https://loige.co/transparent-pixel-response-with-symfony-how-to-track-email-opening/#comments</comments><enclosure url="https://loige.co/og/transparent-pixel-response-with-symfony-how-to-track-email-opening.png" length="0" type="image/png"/></item><item><title>Introducing flickr-set-get a command line app to download photos</title><link>https://loige.co/introducing-flickr-set-get-a-command-line-app-to-download-photos/</link><guid isPermaLink="true">https://loige.co/introducing-flickr-set-get-a-command-line-app-to-download-photos/</guid><description>The flickr-set-get command line app makes it easy to download entire Flickr galleries. It uses the Flickr API and Node.js asynchronous programming to download photos in parallel. The post explains the motivation behind the project, the technologies used, and how the asynchronous code works.</description><pubDate>Mon, 11 May 2015 23:04:50 GMT</pubDate><content:encoded>&lt;p&gt;I recently developed a small command line app that allows you to download an entire gallery from Flickr, it’s called &lt;code&gt;flickr-set-get&lt;/code&gt; and you can find it on &lt;a href=&quot;https://www.npmjs.com/package/flickr-set-get&quot;&gt;NPM&lt;/a&gt; and &lt;a href=&quot;https://github.com/lmammino/flickr-set-get&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;a screenshoot of flickr-set-get&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;798&quot; height=&quot;673&quot; src=&quot;https://loige.co/_astro/687474703a2f2f692e696d6775722e636f6d2f4447457059746c2e706e67.D7dMGS67_Z1UABxu.webp&quot; &gt;&lt;/p&gt;
&lt;h2 id=&quot;why&quot;&gt;Why?&lt;/h2&gt;
&lt;p&gt;To be honest I had myself the need to download a large set of photos (more than 400 photos) from Flickr and I didn’t wanted to do it manually. I also wasn’t able, after a quick search, to find something simple to solve this task. Given that I am currently getting into deep of Node.js this was the perfect chance to develop something practical.&lt;/p&gt;
&lt;h2 id=&quot;how-its-built&quot;&gt;How it’s built?&lt;/h2&gt;
&lt;p&gt;As I said it’s built using Node.js. As part of my learning process, I tried to not reinvent the wheel and to follow “&lt;a href=&quot;http://thenodeway.io&quot;&gt;the Node way&lt;/a&gt;” so I used some very good modules as the foundation to build this app:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/commander&quot;&gt;Commander&lt;/a&gt;, &lt;a href=&quot;https://www.npmjs.com/package/cli&quot;&gt;Cli&lt;/a&gt; and &lt;a href=&quot;https://www.npmjs.com/package/prompt&quot;&gt;Prompt&lt;/a&gt; for the command line facilities (Options/Arguments parsing, help generation, progress bar, receiving input from the user)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/request&quot;&gt;Request&lt;/a&gt;: to simplify the creation of the Http request to call the Flickr APIs&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/async&quot;&gt;Async&lt;/a&gt;: to manage all the asynchronous tasks in parallel and with a configurable level of concurrency (one of the features that in my humble opinion makes node/javascript stand out from the crowd of the interpreted programming languages).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As development tools I also used:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://jscs.info&quot;&gt;JSCS&lt;/a&gt;: to check the code standard I adopted&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://mochajs.org&quot;&gt;Mocha&lt;/a&gt; and &lt;a href=&quot;http://chaijs.com/&quot;&gt;Chai&lt;/a&gt;: test runner and assertion frameworks for the unit testing&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/nock&quot;&gt;Nock&lt;/a&gt;: amazing module to “mock” the Http requests and avoid to hit Flickr servers in my tests&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gotwarlost.github.io/istanbul&quot;&gt;Istanbul&lt;/a&gt;: for the code coverage&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://travis-ci.org&quot;&gt;Travis CI&lt;/a&gt;: continous integration service&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://coveralls.io&quot;&gt;Coveralls&lt;/a&gt;: service to keep track of the coverage changes after every new commit&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gemnasium.com&quot;&gt;Gemnasium&lt;/a&gt;: service that checks your dependencies and alerts you if they get out of date&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;going-asynchronous-and-execute-requests-in-parallel&quot;&gt;Going asynchronous and execute requests in parallel&lt;/h2&gt;
&lt;p&gt;To download a photo from Flickr, starting from a gallery, you need to make several API calls before you have the right URL to download the photo.&lt;/p&gt;
&lt;p&gt;First of all you need to call the &lt;a href=&quot;https://www.flickr.com/services/api/flickr.photosets.getPhotos.html&quot;&gt;flickr.photosets.getPhotos&lt;/a&gt; API method to find out the IDs of all the photos in the set.
Then, to find out the URL of every photo you need to call the &lt;a href=&quot;https://www.flickr.com/services/api/flickr.photos.getSizes.html&quot;&gt;flickr.photos.getSizes&lt;/a&gt; API method. This method gives you all the URLs to download all the different sizes of a given photo. Once you got the URL you can simply use that to download a photo into your local drive.
The first API call is the starting point and then, since you now have all the IDs, you can make all the other requests in parallel.
Thanks to &lt;code&gt;Async&lt;/code&gt; it was very easy to create a &lt;code&gt;task&lt;/code&gt; function that figured out the specific URL of a given photo and then downloads it into a file. Then I just needed to replicate this task for every photo and run all of them in parallel. Thanks to the &lt;code&gt;Async.parallelLimit()&lt;/code&gt; function it’s even possible to run the tasks with a configurable concurrency level.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;flickr-set-get asynchronous requests diagram&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;700&quot; height=&quot;261&quot; src=&quot;https://loige.co/_astro/flickr-set-get-requests-diagram.DkmspPlQ_2l1tdV.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;You can find out how I implemented this specific logic on GitHub: &lt;a href=&quot;https://github.com/lmammino/flickr-set-get/blob/ecaf0d8bea5791cf24c4b71791a7eb1fd2e60bcb/lib/Flickr.js#L212-L253&quot;&gt;https://github.com/lmammino/flickr-set-get/blob/ecaf0d8bea5791cf24c4b71791a7eb1fd2e60bcb/lib/Flickr.js#L212-L253&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;how-to-use-it&quot;&gt;How to use it?&lt;/h2&gt;
&lt;p&gt;If you’re interested on using it I suggest you to read the &lt;a href=&quot;https://github.com/lmammino/flickr-set-get&quot;&gt;official documentation on GitHub&lt;/a&gt;, but it should be quite easy to understand and use it if you are a developer (and it’s not meant to be used by other people who are comfortable with the command line!)&lt;/p&gt;
&lt;h2 id=&quot;current-status&quot;&gt;Current status&lt;/h2&gt;
&lt;p&gt;The project has been developed in a weekend as a “learning project” and tested just by me on few Flickr galleries. It’s to be considered ALPHA quality and I expect it to be fully of bugs and uncovered edge cases.
It’s a small side project anyway so I don’t expect to put so much effort on it again unless it gets adopted by a relevant number of people (which, quite frankly, is really unlikely to happen).
Being an open source project I obviously tried to put in place all the basic infrastructure (tests, code standards, repository, versioning, etc.) to make it easy for other people to work on improving it. Again, more precise informations are included in the &lt;a href=&quot;https://github.com/lmammino/flickr-set-get&quot;&gt;official documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;opinions&quot;&gt;Opinions&lt;/h2&gt;
&lt;p&gt;For me it has been a really good learning experience, especially considering the fact that it was a good scenario to use asynchronous code dealing with several parallel Http requests.
As I still consider it a learning experience I would really love you (probably more experienced than me with Node.js) to give some opinions, critics, new ideas.
I offer the comment box below for this sake… please don’t be too much indulgent :D&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/introducing-flickr-set-get-a-command-line-app-to-download-photos.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/introducing-flickr-set-get-a-command-line-app-to-download-photos.png" width="1200" height="630"/></media:content><category>javascript</category><category>http</category><category>node-js</category><category>api</category><category>flickr</category><author>Luciano Mammino</author><comments>https://loige.co/introducing-flickr-set-get-a-command-line-app-to-download-photos/#comments</comments><enclosure url="https://loige.co/og/introducing-flickr-set-get-a-command-line-app-to-download-photos.png" length="0" type="image/png"/></item><item><title>Reset your MySql server password</title><link>https://loige.co/reset-your-mysql-server-password/</link><guid isPermaLink="true">https://loige.co/reset-your-mysql-server-password/</guid><description>Learn how to reset a lost MySQL root password by restarting the server with disabled security checks. This allows resetting the password directly in the database. Useful when locked out but reduces security temporarily.</description><pubDate>Sun, 30 Mar 2014 09:07:56 GMT</pubDate><content:encoded>&lt;p&gt;Few days ago I learned an interesting trick that allows you to reset the password on a MySql server. This trick is pretty useful in case you have lost (or you haven’t ever had) the password of your MySql root user.&lt;/p&gt;
&lt;p&gt;You just need to throw some commands at the console. Note that I am assuming you are using Ubuntu or some other Debian derivate. Otherwise the commands may change a bit (but not to much I believe).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Reset your MySql server password&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;798&quot; height=&quot;483&quot; src=&quot;https://loige.co/_astro/password_reset.DMBNNv5f_1rQ2vV.webp&quot; &gt;&lt;/p&gt;
&lt;h4 id=&quot;1-stop-the-mysql-daemon&quot;&gt;1. Stop the mysql daemon&lt;/h4&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/etc/init.d/mysql&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;stopRun&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sudo /etc/init.d/mysql stopRun&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h4 id=&quot;2-disable-the-security-checks&quot;&gt;2. Disable the security checks&lt;/h4&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;mysqld_safe&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--skip-grant-tables&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &amp;#x26;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;mysqld_safe --skip-grant-tables &amp;#x26;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.0/en/mysqld-safe.html&quot;&gt;mysqld_safe&lt;/a&gt; command will essentially restarts your MySql server but with the option &lt;code&gt;--skip-grant-tables&lt;/code&gt; it also disables the grant tables used for authentication. You might think that this way the MySql server will deny every access attempt, but it will do the very contrary: it will allow any!
That’s in fact where the trick lies: this way we are able to login to MySql as root (even if we don’t know the password) and edit the MySql users table to reset the root user password.&lt;/p&gt;
&lt;p&gt;Yeah, I didn’t think this was possible before discovering it. But it is, and, even if it feels “insecure”, it might be useful in cases like this.&lt;/p&gt;
&lt;h4 id=&quot;3-login-as-root&quot;&gt;3. Login as root&lt;/h4&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;mysql&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-u&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-p&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;mysql&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;mysql -u root -p mysql&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;It will ask you for a password… Yes, you get it! You can enter whatever you want and it will always grant you access as root!
The last argument (&lt;code&gt;mysql&lt;/code&gt;) specifies you want to access the MySql internal database (where user credentials are stored).&lt;/p&gt;
&lt;h4 id=&quot;4-change-the-root-password&quot;&gt;4. Change the root password&lt;/h4&gt;
&lt;p&gt;You’re using the MySql shell now. Just run:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; user &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;PASSWORD&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;NEW-ROOT-PASSWORD&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;where&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; User=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;root&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;exit;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;update user set password=PASSWORD(&amp;#x22;NEW-ROOT-PASSWORD&amp;#x22;) where User=&amp;#x22;root&amp;#x22;;exit;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;You need to change the &lt;code&gt;&quot;NEW-ROOT-PASSWORD&quot;&lt;/code&gt; with a password of your choice (obviously).&lt;/p&gt;
&lt;h4 id=&quot;5-restart-mysql&quot;&gt;5. Restart MySql&lt;/h4&gt;
&lt;p&gt;You’re back in your bash shell:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;service&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;mysql&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;restart&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sudo service mysql restart&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This will restart the MySql server and will enable the security checks again.&lt;/p&gt;
&lt;p&gt;So that’s all! You can now login into your MySql server with the new password! And try to not lose it again, at least for a while ;)&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/reset-your-mysql-server-password.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/reset-your-mysql-server-password.png" width="1200" height="630"/></media:content><category>security</category><category>mysql</category><category>server</category><author>Luciano Mammino</author><comments>https://loige.co/reset-your-mysql-server-password/#comments</comments><enclosure url="https://loige.co/og/reset-your-mysql-server-password.png" length="0" type="image/png"/></item><item><title>Having fun with Node.js, Slack and Chuck Norris</title><link>https://loige.co/having-fun-with-nodejs-slack-and-chuck-norris/</link><guid isPermaLink="true">https://loige.co/having-fun-with-nodejs-slack-and-chuck-norris/</guid><description>A tutorial was published on how to build a simple Slack bot in Node.js that tells Chuck Norris jokes, for some amusing fun. The bot is open source and available on GitHub and NPM.</description><pubDate>Mon, 14 Sep 2015 22:05:30 GMT</pubDate><content:encoded>&lt;p&gt;I recently wrote a &lt;strong&gt;Slack bot&lt;/strong&gt; in &lt;strong&gt;Node.js&lt;/strong&gt; in collaboration with one of my favourite web development websites: the amazing &lt;a href=&quot;https://scotch.io&quot;&gt;Scotch.io&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It’s a simple and funny experiment I have done in my free time to learn something new. It’s nothing special but it will add a bit of fun inside your Slack organisation… &lt;em&gt;Who doesn’t want to have a bot that tells random jokes about Chuck Norris in his own Company chat room?&lt;/em&gt; :)&lt;/p&gt;
&lt;p&gt;The bot is available on Github (&lt;a href=&quot;https://github.com/lmammino/norrisbot&quot;&gt;lmammino/norrisbot&lt;/a&gt;) and on NPM (&lt;a href=&quot;https://www.npmjs.com/package/norrisbot&quot;&gt;norrisbot&lt;/a&gt;) and it can be easily installed configured and installed on every VPS and even on Heroku (using the free plan!).&lt;/p&gt;
&lt;p&gt;If you are interested in knowing how it works, in understanding the code and in learning how to deploy it on Heroku, you should definitely read the article we published on Scotch.io:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://scotch.io/tutorials/building-a-slack-bot-with-node-js-and-chuck-norris-super-powers&quot;&gt;Building a Slack Bot with Node.js and Chuck Norris Super Powers&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://scotch.io/tutorials/building-a-slack-bot-with-node-js-and-chuck-norris-super-powers&quot;&gt;&lt;img alt=&quot;Building a Slack bot with Node.js and Chuck Norris Super Powers&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1200&quot; height=&quot;500&quot; src=&quot;https://loige.co/_astro/slacker.BzYInd3g_A4lDc.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Enjoy it and feel free to leave your comments here or on the article.&lt;/p&gt;
&lt;p&gt;Cheers!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/having-fun-with-nodejs-slack-and-chuck-norris.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/having-fun-with-nodejs-slack-and-chuck-norris.png" width="1200" height="630"/></media:content><category>node-js</category><category>slack</category><category>collaboration</category><author>Luciano Mammino</author><comments>https://loige.co/having-fun-with-nodejs-slack-and-chuck-norris/#comments</comments><enclosure url="https://loige.co/og/having-fun-with-nodejs-slack-and-chuck-norris.png" length="0" type="image/png"/></item><item><title>8 invitations to try Keybase.io</title><link>https://loige.co/8-invitations-to-try-keybase-io/</link><guid isPermaLink="true">https://loige.co/8-invitations-to-try-keybase-io/</guid><description>Keybase.io is a new service that combines asymmetric cryptography with a social network. It allows users to easily share public keys and authenticate messages by linking keys to profiles on Twitter, GitHub, Reddit, etc. The service provides encrypted messaging and bitcoin wallet pairing to make adopting cryptography seamless.</description><pubDate>Tue, 26 May 2015 22:25:45 GMT</pubDate><content:encoded>&lt;p&gt;Hello dear developers,
today I finally got my invitation to access the private beta of &lt;a href=&quot;https://keybase.io&quot;&gt;Keybase.io&lt;/a&gt;! 😎 🎉
For those who are not aware of this new service, Keybase.io is a website and a command line application that makes easier to adopt asymmetric cryptography to encrypt and authenticate messages. But it’s not just this, it’s also a &lt;em&gt;“directory of people”&lt;/em&gt;, as they like to say. It’s like a social network, where everyone can easily share its public key and attach it to its social profiles (like Twitter, Github or Reddit). You can also pair your bitcoin address with it…&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Keybase.io illustration&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;303&quot; src=&quot;https://loige.co/_astro/keybase-io-robot.AxXlHUb8_Z1vADdP.webp&quot; &gt;
…and furthermore the website is full of wonderful illustrations a-la-Dropbox :D&lt;/p&gt;
&lt;h2 id=&quot;a-quick-demo&quot;&gt;A quick demo&lt;/h2&gt;
&lt;p&gt;Just to give you a practical idea of how it works, let’s suppose I want to send a super-secret message to my twitter friend Daniel Li (&lt;a href=&quot;https://twitter.com/d4nyll&quot;&gt;@d4nyll&lt;/a&gt;).
Once I have the Keybase command line app installed (and configured) I can just run:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;keybase&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;encrypt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;twitter://d4nyll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-m&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Hey pal, I finally crafted the perfect plan to rule this World. Give me a ring-3&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$ keybase encrypt twitter://d4nyll -m &amp;#x22;Hey pal, I finally crafted the perfect plan to rule this World. Give me a ring-3&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;and it will print out a weird message that only Daniel, with his private key will be able to decrypt:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;-----BEGIN PGP MESSAGE-----&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Comment: GPGTools - https://gpgtools.org&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;hQEMA8ev5aoujuM4AQgAo5xTWEBmso9cNpAt4e9W854dq9LPR6pB3LoBTAKO8QBI&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;pc/+UWezWCX49SX4zO2omrqRCMrtNy4UAeU9WyAxGQDTIRGcmiOM0p+JuInG9P2S&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;D4YCz2HwX6p7/P3gLuRpqU8VteInXWeIAFFj7piaCZSeHG8w1/wiPhx46GjByqUJ&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;80dzrew7o0bxg3Fi5uuFlnKEIOMUgjMWbCGEBArvdeGO1XElrSMU475klUfrvFyS&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Z3106Np2VMDdIfQEbpomCBjqj+woc36Cfbx3aPzI8Gi+dmYd3zP8PsMgjcbIuxb2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;quAzUtQwcJIAKR35E4l0OUzC0sCNLgddUCLqCoBCttJ+AWeGsGx+PlVWpXTVOr+j&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Udc+wIYvblTxaogQVJLSl8HF/9321gp3duPF9CKWinbQfw6Rh7UQX6JoRaXBgVo3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;tn2k+/Iq1gDZhyoeAq7pSGzV0J3GPPiY+SVbmjjzQIftW7pvuIhDT1iKKMloUyyt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Y+yURG9sqr92QGVDLX/x&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;=mmvL&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;-----END PGP MESSAGE-----&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;-----BEGIN PGP MESSAGE-----Comment: GPGTools - https://gpgtools.orghQEMA8ev5aoujuM4AQgAo5xTWEBmso9cNpAt4e9W854dq9LPR6pB3LoBTAKO8QBIpc/+UWezWCX49SX4zO2omrqRCMrtNy4UAeU9WyAxGQDTIRGcmiOM0p+JuInG9P2SD4YCz2HwX6p7/P3gLuRpqU8VteInXWeIAFFj7piaCZSeHG8w1/wiPhx46GjByqUJ80dzrew7o0bxg3Fi5uuFlnKEIOMUgjMWbCGEBArvdeGO1XElrSMU475klUfrvFySZ3106Np2VMDdIfQEbpomCBjqj+woc36Cfbx3aPzI8Gi+dmYd3zP8PsMgjcbIuxb2quAzUtQwcJIAKR35E4l0OUzC0sCNLgddUCLqCoBCttJ+AWeGsGx+PlVWpXTVOr+jUdc+wIYvblTxaogQVJLSl8HF/9321gp3duPF9CKWinbQfw6Rh7UQX6JoRaXBgVo3tn2k+/Iq1gDZhyoeAq7pSGzV0J3GPPiY+SVbmjjzQIftW7pvuIhDT1iKKMloUyytY+yURG9sqr92QGVDLX/x=mmvL-----END PGP MESSAGE-----&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now I just need to copy and paste this message to Daniel through Skype, an email, Slack or whatever.&lt;/p&gt;
&lt;p&gt;Daniel will be able to easily decrypt the message through the same command line app or though the Keybase website.&lt;/p&gt;
&lt;p&gt;The clear advantage is that I don’t need to go around and find a person public key every time I want to send an encrypted message to someone. With Keybase I just have to remember his username from Twitter, Github or whatever.&lt;/p&gt;
&lt;p&gt;It’s still a little bit boring that I have to transfer my message manually, but the Keybase team has already developed a set of &lt;a href=&quot;https://keybase.io/docs/api/1.0&quot;&gt;APIs&lt;/a&gt; that, I guess, makes possible to fill the gap in terms of integration with other messaging apps.&lt;/p&gt;
&lt;p&gt;The command line application has a lot of other handy features like messages certification and verification (signature) and in case you dislike the command line (which is unlikely if you are reading this blog), you can do pretty much everything directly on the website.&lt;/p&gt;
&lt;h2 id=&quot;do-you-want-to-give-it-a-try&quot;&gt;Do you want to give it a try?&lt;/h2&gt;
&lt;p&gt;As you probably have guessed from the title of this post and the first paragraph Keybase is still in private beta and you need an invite to use it. If you haven’t already received your &lt;strong&gt;I have 8 invite code that I am willing to share&lt;/strong&gt;. They go to the &lt;strong&gt;first 8 persons who will leave a comment*&lt;/strong&gt; here 😉&lt;/p&gt;
&lt;div style=&quot;background:rgb(226, 114, 114); color: #fff; padding: 1em; margin: 1em&quot;&gt;
    &lt;strong&gt;Update (27 may 2015 12:20 GMT)&lt;/strong&gt;: Invites are over :( &lt;br&gt;I will try to request new ones. If you want you can keep commenting and I will give new eventual invites in the order of entry.
&lt;/div&gt;
&lt;p&gt;What are you waiting for?&lt;/p&gt;
&lt;p&gt;PS: In case you want to “Track” (verify+follow) me on Keybase, check out &lt;a href=&quot;https://keybase.io/loige&quot;&gt;my Keybase profile&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/8-invitations-to-try-keybase-io.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/8-invitations-to-try-keybase-io.png" width="1200" height="630"/></media:content><category>security</category><category>cryptography</category><author>Luciano Mammino</author><comments>https://loige.co/8-invitations-to-try-keybase-io/#comments</comments><enclosure url="https://loige.co/og/8-invitations-to-try-keybase-io.png" length="0" type="image/png"/></item><item><title>Symfony, edit the Response globally using the Kernel Response event</title><link>https://loige.co/symfony-edit-the-response-globally-using-the-kernel-response-event/</link><guid isPermaLink="true">https://loige.co/symfony-edit-the-response-globally-using-the-kernel-response-event/</guid><description>The Symfony HttpKernel Component allows interacting with the response generation through events. The Kernel Response event permits modifying the response before sending it out. Two examples show how to use it to add custom headers and cookies without touching controller logic.</description><pubDate>Sat, 21 Feb 2015 01:12:00 GMT</pubDate><content:encoded>&lt;p&gt;One of the things I like most of the Symfony framework is its &lt;a href=&quot;https://packagist.org/packages/symfony/http-kernel&quot;&gt;Http Kernel component&lt;/a&gt;. Not only it does offer a very straightforward abstraction to handle requests and responses in an object-oriented way but it also allows you to interact with the whole response generation process through &lt;a href=&quot;http://symfony.com/doc/current/components/http_kernel/introduction.html#creating-an-event-listener&quot;&gt;events&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://symfony.com/doc/current/components/http_kernel/introduction.html&quot;&gt;&lt;img alt=&quot;Symfony Http Kernel component overview&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;690&quot; height=&quot;414&quot; src=&quot;https://loige.co/_astro/symfony-http-kernel-component-overview-scheme.BXQbSu_c_vDs9v.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This approach is very convenient and flexible and in fact the Http Kernel component is the foundation of the Symfony framework but also of several other famous frameworks (Silex, Laravel) and CMSes (Drupal, BackBee CMS).&lt;/p&gt;
&lt;h2 id=&quot;the-kernel-response-event&quot;&gt;The Kernel Response event&lt;/h2&gt;
&lt;p&gt;One event that I’ve been using a lot lately is the &lt;a href=&quot;http://api.symfony.com/master/Symfony/Component/HttpKernel/Event/FilterResponseEvent.html&quot;&gt;Kernel Response event&lt;/a&gt; which allows you to edit the response after it has been generated.&lt;/p&gt;
&lt;p&gt;Thanks to this event you can easily modify the response object (cookies, headers, content, etc.) before it gets sent out to the user without affecting the specific logic of every controller thus avoiding code cluttering and duplication.&lt;/p&gt;
&lt;p&gt;I will present two different real case scenarios to show how useful (and simple) it is.&lt;/p&gt;
&lt;h3 id=&quot;example-1-add-custom-http-headers-to-notify-remaining-api-calls&quot;&gt;Example 1. Add custom Http headers to notify remaining api calls&lt;/h3&gt;
&lt;p&gt;Let’s suppose we developed a wonderful rate limited api and now we want to add some custom headers to notify the user about how much he is using the API.
It seems a good idea to copy the approach adopted by the GitHub APIs and add three custome headers: &lt;code&gt;X-RateLimit-Limit&lt;/code&gt; (maximum number of requests per period), &lt;code&gt;X-RateLimit-Remaining&lt;/code&gt; (remaining requests in the current period) and &lt;code&gt;X-RateLimit-Reset&lt;/code&gt; (the timestamp on which the current period ends).&lt;/p&gt;
&lt;p&gt;As I don’t want to implement a fully working solution here let’s assume we have already written a rate limit checker service registered as &lt;code&gt;rate_limit_checker&lt;/code&gt; that implements the following interface:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;RateLimitCheckerInterface&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getRateLimit&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getRateLimitRemaining&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getRateLimitReset&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;interface RateLimitCheckerInterface{  public function getRateLimit();  public function getRateLimitRemaining();    public function getRateLimitReset();}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Let’s now write our &lt;code&gt;RateLimitHeadersListener&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Symfony\Component\HttpKernel\Event\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;FilterResponseEvent&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;RateLimitHeadersListener&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$rateLimitChecker&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;__construct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;RateLimitCheckerInterface&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$rateLimitChecker&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;){&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;rateLimitChecker&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$rateLimitChecker&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;onKernelResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;FilterResponseEvent&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$event&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$headers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$event&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;headers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$headers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;X-RateLimit-Limit&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;rateLimitChecker&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getRateLimit&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$headers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;X-RateLimit-Remaining&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;rateLimitChecker&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getRateLimitRemaining&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$headers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;X-RateLimit-Reset&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;rateLimitChecker&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getRateLimitReset&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;use Symfony\Component\HttpKernel\Event\FilterResponseEvent;final class RateLimitHeadersListener{  private $rateLimitChecker;  public function __construct(      RateLimitCheckerInterface $rateLimitChecker    ){      $this-&gt;rateLimitChecker = $rateLimitChecker;    }    public function onKernelResponse(FilterResponseEvent $event)    {        $headers = $event-&gt;getResponse()-&gt;headers;        $headers-&gt;set(          &amp;#x27;X-RateLimit-Limit&amp;#x27;,            $this-&gt;rateLimitChecker-&gt;getRateLimit()        );        $headers-&gt;set(          &amp;#x27;X-RateLimit-Remaining&amp;#x27;,            $this-&gt;rateLimitChecker-&gt;getRateLimitRemaining()        );        $headers-&gt;set(          &amp;#x27;X-RateLimit-Reset&amp;#x27;,            $this-&gt;rateLimitChecker-&gt;getRateLimitReset()        );    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now we need to register the listener as a tagged service:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;services.yml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;rate_limit_listener&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;RateLimitHeadersListener&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;arguments&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@rate_limit_checker&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;tags&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;- {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;kernel.event_listener&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;kernel.response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;method&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;onKernelResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;rate_limit_listener:  class: RateLimitHeadersListener  arguments: [&amp;#x27;@rate_limit_checker&amp;#x27;]  tags:    - {        name: kernel.event_listener,        event: kernel.response,        method: onKernelResponse,      }&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That’s it. Really straightforward, isn’t it?
Should be clear now that, by using this event based approach, we don’t have to touch the logic of every single controller.&lt;/p&gt;
&lt;p&gt;Take a small break and get ready to jump to another example.&lt;/p&gt;
&lt;h3 id=&quot;example-2-create-a-cookie-to-track-referrals&quot;&gt;Example 2. Create a cookie to track referrals&lt;/h3&gt;
&lt;p&gt;Well, now imagine that we have to build an affiliate program based on referral links (&lt;a href=&quot;https://sbaam.com/affiliates?_r=9oj&quot;&gt;I did it&lt;/a&gt; lately).&lt;/p&gt;
&lt;p&gt;The general idea is that our affiliates are identified by an ID that they can attach to every url of the website as query parameter. This way every URL of our website can be an entry point for our visitors and our affiliates are free to promote the content that is more relevant for them.
Doing so we need to verify every possibile request to check for the referrral parameter and keep track of the whole session of the visitor (or even better monitor him for a given amount of days) to see if his visits converts into some kind of action for which we have to reward the affiliate.
To write a more formal specification we have to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Allow any of our affiliates to share links with a special referral code as query parameter: &lt;code&gt;?_ref=&amp;#x3C;REF_ID&gt;&lt;/code&gt; (where &lt;code&gt;REF_ID&lt;/code&gt; is the unique id of the affiliate).&lt;/li&gt;
&lt;li&gt;Intercept visitor referred by affiliates through the referral parameter and identify the referral&lt;/li&gt;
&lt;li&gt;Create a cookie to track the referred visitor for 30 days&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Again we can use the Kernel Response Event and create a dedicated listener for this task. Before doing so suppose we have already developed a mechanism to store our affiliates and that we have coded a &lt;code&gt;affiliate_repository&lt;/code&gt; service which implementats of the following interface:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;AffiliateRepositoryInterface&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;findOneById&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;interface AffiliateRepositoryInterface{  public function findOneById($id);}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now let’s write our listener to intercept clicks on referral links:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;AffiliateLinkClickListener&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$affiliateRepository&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;__construct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;AffiliateRepositoryInterface&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$affiliateRepository&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;){&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;affiliateRepository&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$affiliateRepository&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;onKernelResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;FilterResponseEvent&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$event&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$request&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$event&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getRequest&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$event&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 1.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$request&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;has&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;_ref&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$affiliateId&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$request&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;_ref&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 2.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; !== &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;affiliateRepository&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;findOneById&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$affiliateId&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 3.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$cookie&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Cookie&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;_ref&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$affiliateId&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;\DateTime&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;+30 days&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;headers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;setCookie&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$cookie&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;final class AffiliateLinkClickListener{  private $affiliateRepository;    public function __construct(      AffiliateRepositoryInterface $affiliateRepository    ){      $this-&gt;affiliateRepository = $affiliateRepository;    }    public function onKernelResponse(FilterResponseEvent $event)    {      $request = $event-&gt;getRequest();        $response = $event-&gt;getResponse();        // 1.        if ($request-&gt;query-&gt;has(&amp;#x27;_ref&amp;#x27;)) {          $affiliateId = $request-&gt;query-&gt;get(&amp;#x27;_ref&amp;#x27;);            // 2.            if (null !== $this-&gt;affiliateRepository-&gt;findOneById($affiliateId)) {              // 3.                $cookie = new Cookie(&amp;#x27;_ref&amp;#x27;, $affiliateId, new \DateTime(&amp;#x27;+30 days&amp;#x27;));                $response-&gt;headers-&gt;setCookie($cookie);            }        }    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The code is pretty simple here:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We check if there’s a &lt;code&gt;_ref&lt;/code&gt; parameter in the current request&lt;/li&gt;
&lt;li&gt;If so we check if we have an affiliate with the id found in the &lt;code&gt;_ref&lt;/code&gt; parameter&lt;/li&gt;
&lt;li&gt;If that’s the case we create a cookie that will allow us to keep track of the referral for 30 days.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Obviously don’t forget to register the listener as a tagged service:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;services.yml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;affiliate_link_click_listener&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;AffiliateLinkClickListener&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;arguments&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@affiliate_repository&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;tags&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;- {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;kernel.event_listener&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;kernel.response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;method&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;onKernelResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;affiliate_link_click_listener:  class: AffiliateLinkClickListener  arguments: [&amp;#x27;@affiliate_repository&amp;#x27;]  tags:    - {        name: kernel.event_listener,        event: kernel.response,        method: onKernelResponse,      }&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;As I said, this mechanisms allows you to track the reference but you also need to track any conversion and check the cookie to see if it has been generated by some affiliate.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;As in every tutorial, bear in mind that the code is just a sample to give you a general idea about an approach you can follow to solve some generic problem. You need to adapt it to your use case and consider relevant factors such as security, testing, etc.&lt;/p&gt;
&lt;p&gt;Let me know what you think with a comment (&lt;a href=&quot;#disqus_thread&quot;&gt;comments&lt;/a&gt;) and feel free to suggest other real-life use cases for the Kernel Response Event.&lt;/p&gt;
&lt;p&gt;Thanks!&lt;/p&gt;
&lt;p&gt;PS: Huge thanks to &lt;a href=&quot;http://twitter.com/AxelLessio&quot;&gt;@AxelLessio&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/javiereguiluz&quot;&gt;@JavierEguiluz&lt;/a&gt; for taking the time to review my very bad english ;)&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/symfony-edit-the-response-globally-using-the-kernel-response-event.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/symfony-edit-the-response-globally-using-the-kernel-response-event.png" width="1200" height="630"/></media:content><category>php</category><category>symfony</category><category>http</category><author>Luciano Mammino</author><comments>https://loige.co/symfony-edit-the-response-globally-using-the-kernel-response-event/#comments</comments><enclosure url="https://loige.co/og/symfony-edit-the-response-globally-using-the-kernel-response-event.png" length="0" type="image/png"/></item><item><title>Writing a new Extractor for PHPoAuthUserData</title><link>https://loige.co/writing-a-new-extractor-for-php-oauth-user-data/</link><guid isPermaLink="true">https://loige.co/writing-a-new-extractor-for-php-oauth-user-data/</guid><description>This post explains how to add support for Instagram to the PHPoAuthUserData library by writing a dedicated extractor class. It illustrates the concepts of loaders, normalizers and mapping to extract user profile data from the Instagram API.</description><pubDate>Mon, 10 Feb 2014 17:23:54 GMT</pubDate><content:encoded>&lt;p&gt;In my &lt;a href=&quot;http://loige.com/new-php-library-php-oauth-user-data/&quot;&gt;previous post&lt;/a&gt; I introduced my latest library &lt;a href=&quot;https://github.com/Oryzone/PHPoAuthUserData&quot;&gt;PHPoAuthUserData&lt;/a&gt; that allows to abstract the process of
extracting user profile data from various OAuth providers (&lt;em&gt;Facebook&lt;/em&gt;, &lt;em&gt;Twitter&lt;/em&gt;, &lt;em&gt;Linkedin&lt;/em&gt;, etc).&lt;/p&gt;
&lt;p&gt;The library still need a lot of work, especially to write the logic to extract data from all the services available in the &lt;a href=&quot;https://github.com/Lusitanian/PHPoAuthLib&quot;&gt;parent OAuth library&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At the moment the library supports only the most common OAuth providers. I would be glad to support all the following services:&lt;/p&gt;
&lt;p&gt;Amazon, BitBucket, BitLy, Box, Dailymotion, Dropbox, Etsy, FitBit, Flickr, Foursquare, GitHub, Google, Heroku, Mailchimp, Microsoft, PayPal, Reddit, RunKeeper, SoundCloud, Tumblr, Vkontakte, Yammer.&lt;/p&gt;
&lt;p&gt;So that’s a lot of work! And yes, of course I would be glad to share it with someone interested in using the library.&lt;/p&gt;
&lt;p&gt;This article illustrates how to add support for a new service by writing a dedicate &lt;strong&gt;extractor&lt;/strong&gt; class. It’s really simple so stick with me and you will be able to submit your pull request in minutes!&lt;/p&gt;
&lt;h2 id=&quot;what-is-an-extractor&quot;&gt;What is an extractor&lt;/h2&gt;
&lt;p&gt;Extractors defines the logic to request information to a given service API and to normalize the received data according to a common &lt;a href=&quot;https://github.com/Oryzone/PHPoAuthUserData/blob/master/src/OAuth/UserData/Extractor/ExtractorInterface.php&quot;&gt;interface&lt;/a&gt;.
The most basic way to define an extractor is to write a class that implements the &lt;a href=&quot;https://github.com/Oryzone/PHPoAuthUserData/blob/master/src/OAuth/UserData/Extractor/ExtractorInterface.php&quot;&gt;ExtractorInterface&lt;/a&gt; (that is pretty self-explanatory).&lt;/p&gt;
&lt;p&gt;You could extend the class &lt;a href=&quot;https://github.com/Oryzone/PHPoAuthUserData/blob/master/src/OAuth/UserData/Extractor/Extractor.php&quot;&gt;Extractor&lt;/a&gt; that implements most of the needed code to get you started. Anyway, extractors should &lt;strong&gt;really&lt;/strong&gt; extend the class &lt;a href=&quot;https://github.com/Oryzone/PHPoAuthUserData/blob/master/src/OAuth/UserData/Extractor/LazyExtractor.php&quot;&gt;LazyExtractor&lt;/a&gt; where possible
because this class acts as a boilerplate to define highly optimized extractors. It easily allows you to implement extractors that &lt;strong&gt;lazy loads&lt;/strong&gt; data (perform requests only when needed to) and &lt;strong&gt;caches&lt;/strong&gt; data (does not make the same request more than once and avoids normalizing the same data more than once). Everything is done behind the scenes, so you’ll need to focus only on methods that define how to make
requests and how to normalize data.&lt;/p&gt;
&lt;p&gt;To understand how to write a new extractor by adopting the &lt;a href=&quot;https://github.com/Oryzone/PHPoAuthUserData/blob/master/src/OAuth/UserData/Extractor/LazyExtractor.php&quot;&gt;LazyExtractor&lt;/a&gt; we need to clarify some concepts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Supported fields&lt;/strong&gt;: an array of the fields that can be extracted (you should use field constants from the &lt;a href=&quot;https://github.com/Oryzone/PHPoAuthUserData/blob/master/src/OAuth/UserData/Extractor/ExtractorInterface.php&quot;&gt;ExtractorInterface&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Loaders&lt;/strong&gt;: methods whose responsibility is to trigger the proper request to the OAuth provider endpoint to load a specific set of raw data. Generally you need to define a loader for each block of information that could be retrieved from the endpoint. this methods must have the suffix &lt;code&gt;Loader&lt;/code&gt; in their name.
Most of the service will allow you to retrieve all the user data with a single request, so, in this cases, you would have only a single loader method (eg: &lt;code&gt;profileLoader&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Normalizers&lt;/strong&gt;: methods that accept raw data (the one previously fetched by some loader method) and uses it to extract the value for a given field.
Usually you have a normalizer for each supported field. Normalizers methods must have the suffix &lt;code&gt;Normalizer&lt;/code&gt; (eg. &lt;code&gt;uniqueIdNormalizer&lt;/code&gt; or &lt;code&gt;descriptionNormalizer&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LoadersMap&lt;/strong&gt;: an array that associates supported fields (keys) to loaders methods (values). Loaders methods must be referenced without the &lt;code&gt;Loader&lt;/code&gt; suffix.
Most of the time, if you have only the &lt;code&gt;profileLoader&lt;/code&gt; loader you will have an array with all fields mapping to the string &lt;code&gt;profile&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NormalizersMap&lt;/strong&gt;: an array that associates supported fields (keys) to the related normalizer methods (values). Normalizers methods must be referenced without the &lt;code&gt;Normalizer&lt;/code&gt; suffix. It’s highly suggested to use the same name of the field for its related normalizer, so, most of the time, you will end up by having an array that maps field constants to the same field constant (eg. &lt;code&gt;array(self::FIELD_UNIQUE_ID =&gt; self::FIELD_UNIQUE_ID)&lt;/code&gt;) for
every supported field.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you defined &lt;em&gt;Supported Fields&lt;/em&gt;, &lt;em&gt;Loaders&lt;/em&gt;, &lt;em&gt;Normalizers&lt;/em&gt;, &lt;em&gt;Loaders Map&lt;/em&gt; and &lt;em&gt;Normalizers Map&lt;/em&gt; from within your new extractor class you must
wire them to the underlying logic by passing them to the parent constructor. So if you defined methods such as &lt;code&gt;getSupportedField&lt;/code&gt;, &lt;code&gt;getLoadersMap&lt;/code&gt; and &lt;code&gt;getNormalizersMap&lt;/code&gt;
you will end up with a constructor like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;__construct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;parent&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;__construct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getLoadersMap&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getNormalizersMap&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getSupportedFields&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public function __construct(){    parent::__construct(        self::getLoadersMap(),        self::getNormalizersMap(),        self::getSupportedFields()    );}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;But let’s see how I built the &lt;a href=&quot;https://github.com/Oryzone/PHPoAuthUserData/blob/master/src/OAuth/UserData/Extractor/Instagram.php&quot;&gt;Instagram extractor&lt;/a&gt; to have a better understanding on the whole process.&lt;/p&gt;
&lt;h2 id=&quot;writing-the-instagram-extractor&quot;&gt;Writing the Instagram extractor&lt;/h2&gt;
&lt;p&gt;First of all I had a look on &lt;a href=&quot;http://instagram.com/developer/api-console/&quot;&gt;a bit of documentation&lt;/a&gt; to find out what kind of data can be extracted from Instagram users.&lt;/p&gt;
&lt;p&gt;So I discovered that the request to retrieve information about the user is: &lt;code&gt;/users/self&lt;/code&gt; and its response is a json object that looks like the following:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;meta&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;code&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;200&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;username&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;johnnydonny&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;bio&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;A life on the edge&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;website&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;http://blog.johnnydonny.com&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;profile_picture&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;http://images.ak.instagram.com/profiles/profile_weird_numbers.jpg&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;full_name&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;John Doe&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;counts&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;media&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;131&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;followed_by&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;80&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;follows&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;64&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;1111222333&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{  &amp;#x22;meta&amp;#x22;: {    &amp;#x22;code&amp;#x22;: 200  },  &amp;#x22;data&amp;#x22;: {    &amp;#x22;username&amp;#x22;: &amp;#x22;johnnydonny&amp;#x22;,    &amp;#x22;bio&amp;#x22;: &amp;#x22;A life on the edge&amp;#x22;,    &amp;#x22;website&amp;#x22;: &amp;#x22;http://blog.johnnydonny.com&amp;#x22;,    &amp;#x22;profile_picture&amp;#x22;: &amp;#x22;http://images.ak.instagram.com/profiles/profile_weird_numbers.jpg&amp;#x22;,    &amp;#x22;full_name&amp;#x22;: &amp;#x22;John Doe&amp;#x22;,    &amp;#x22;counts&amp;#x22;: {      &amp;#x22;media&amp;#x22;: 131,      &amp;#x22;followed_by&amp;#x22;: 80,      &amp;#x22;follows&amp;#x22;: 64    },    &amp;#x22;id&amp;#x22;: &amp;#x22;1111222333&amp;#x22;  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;So I understood wich fields can be mapped and started writing the &lt;code&gt;Instagram&lt;/code&gt; class under the &lt;code&gt;OAuth\UserData\Extractor&lt;/code&gt; namespace.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;php&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;OAuth\UserData\Extractor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Instagram&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;LazyExtractor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;?phpnamespace OAuth\UserData\Extractor;class Instagram extends LazyExtractor{  //...}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;First of all I wrote the method &lt;code&gt;profileLoader&lt;/code&gt; and added a class constant that defines the url of the request.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;REQUEST_PROFILE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/users/self&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;profileLoader&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;json_decode&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;service&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;REQUEST_PROFILE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const REQUEST_PROFILE = &amp;#x27;/users/self&amp;#x27;;protected function profileLoader(){  return json_decode($this-&gt;service-&gt;request(self::REQUEST_PROFILE), true);}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Each extractor has access to the property &lt;code&gt;$this-&gt;service&lt;/code&gt; that is an instance of the specific OAuth service from the parent library (&lt;code&gt;OAuth\OAuth2\Service\Instagram&lt;/code&gt;) in this case. With this instance you can easily make request to the provider API endpoint.&lt;/p&gt;
&lt;p&gt;Then I added the &lt;code&gt;getSupportedFields&lt;/code&gt; method:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getSupportedFields&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;FIELD_UNIQUE_ID&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;FIELD_USERNAME&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;FIELD_FULL_NAME&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;FIELD_FIRST_NAME&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;FIELD_LAST_NAME&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;FIELD_DESCRIPTION&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;FIELD_WEBSITES&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;FIELD_IMAGE_URL&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;FIELD_PROFILE_URL&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;FIELD_EXTRA&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;protected static function getSupportedFields(){  return array(    self::FIELD_UNIQUE_ID,    self::FIELD_USERNAME,    self::FIELD_FULL_NAME,    self::FIELD_FIRST_NAME,    self::FIELD_LAST_NAME,    self::FIELD_DESCRIPTION,    self::FIELD_WEBSITES,    self::FIELD_IMAGE_URL,    self::FIELD_PROFILE_URL,    self::FIELD_EXTRA  );}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The fields &lt;em&gt;first_name&lt;/em&gt;, &lt;em&gt;last_name&lt;/em&gt; and &lt;em&gt;profile_url&lt;/em&gt; are not directly available on the json response but are easy to reconstruct by using the &lt;em&gt;full_name&lt;/em&gt; and &lt;em&gt;username&lt;/em&gt; fields.&lt;/p&gt;
&lt;p&gt;Than I started writing all the normalizer methods to map the raw data to the respective supported fields:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;uniqueIdNormalizer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;isset&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;data&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]) ? &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;data&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] : &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;usernameNormalizer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;isset&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;data&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;username&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]) ? &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;data&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;username&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] : &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fullNameNormalizer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;isset&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;data&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;full_name&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]) ? &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;data&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;full_name&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] : &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;firstNameNormalizer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$fullName&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getField&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;FIELD_FULL_NAME&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$fullName&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$names&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;explode&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos; &apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$fullName&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$names&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;lastNameNormalizer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$fullName&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getField&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;FIELD_FULL_NAME&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$fullName&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$names&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;explode&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos; &apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$fullName&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$names&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;sizeof&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$names&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) - &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;descriptionNormalizer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;isset&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;data&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;bio&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]) ? &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;data&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;bio&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] : &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;websitesNormalizer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$websites&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;isset&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;data&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;website&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;])) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$websites&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[] = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;data&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;website&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$websites&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;profileUrlNormalizer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$username&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getField&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;FIELD_USERNAME&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; !== &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$username&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;sprintf&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;http://instagram.com/%s&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$username&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;imageUrlNormalizer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;isset&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;data&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;profile_picture&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]) ? &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;data&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;profile_picture&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] : &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;extraNormalizer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;ArrayUtils&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;removeKeys&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;data&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;username&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;full_name&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;website&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;profile_picture&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;bio&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;protected function uniqueIdNormalizer($data){  return isset($data[&amp;#x27;data&amp;#x27;][&amp;#x27;id&amp;#x27;]) ? $data[&amp;#x27;data&amp;#x27;][&amp;#x27;id&amp;#x27;] : null;}protected function usernameNormalizer($data){  return isset($data[&amp;#x27;data&amp;#x27;][&amp;#x27;username&amp;#x27;]) ? $data[&amp;#x27;data&amp;#x27;][&amp;#x27;username&amp;#x27;] : null;}protected function fullNameNormalizer($data){  return isset($data[&amp;#x27;data&amp;#x27;][&amp;#x27;full_name&amp;#x27;]) ? $data[&amp;#x27;data&amp;#x27;][&amp;#x27;full_name&amp;#x27;] : null;}protected function firstNameNormalizer(){  $fullName = $this-&gt;getField(self::FIELD_FULL_NAME);  if ($fullName) {    $names = explode(&amp;#x27; &amp;#x27;, $fullName);    return $names[0];  }  return null;}protected function lastNameNormalizer(){  $fullName = $this-&gt;getField(self::FIELD_FULL_NAME);  if ($fullName) {    $names = explode(&amp;#x27; &amp;#x27;, $fullName);      return $names[sizeof($names) - 1];  }  return null;}protected function descriptionNormalizer($data){  return isset($data[&amp;#x27;data&amp;#x27;][&amp;#x27;bio&amp;#x27;]) ? $data[&amp;#x27;data&amp;#x27;][&amp;#x27;bio&amp;#x27;] : null;}protected function websitesNormalizer($data){  $websites = array();  if (isset($data[&amp;#x27;data&amp;#x27;][&amp;#x27;website&amp;#x27;])) {    $websites[] = $data[&amp;#x27;data&amp;#x27;][&amp;#x27;website&amp;#x27;];  }  return $websites;}protected function profileUrlNormalizer(){  $username = $this-&gt;getField(self::FIELD_USERNAME);  if (null !== $username) {    return sprintf(&amp;#x27;http://instagram.com/%s&amp;#x27;, $username);  }  return null;}protected function imageUrlNormalizer($data){  return isset($data[&amp;#x27;data&amp;#x27;][&amp;#x27;profile_picture&amp;#x27;]) ? $data[&amp;#x27;data&amp;#x27;][&amp;#x27;profile_picture&amp;#x27;] : null;}protected function extraNormalizer($data){  return ArrayUtils::removeKeys($data[&amp;#x27;data&amp;#x27;], array(            &amp;#x27;id&amp;#x27;,            &amp;#x27;username&amp;#x27;,            &amp;#x27;full_name&amp;#x27;,            &amp;#x27;website&amp;#x27;,            &amp;#x27;profile_picture&amp;#x27;,            &amp;#x27;bio&amp;#x27;,  ));}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Notice that each normalizer must return &lt;code&gt;null&lt;/code&gt; if the field is not defined. That’s a best pratice to follow for safety.&lt;/p&gt;
&lt;p&gt;Also notice that the &lt;code&gt;extraNormalizer&lt;/code&gt; method has the purpose to keep track of all the fields that could not be mapped to the &lt;code&gt;ExtractorInterface&lt;/code&gt; fields. So we use the &lt;code&gt;OAuth\UserData\Utils\ArrayUtils::removeKeys&lt;/code&gt; method to simply remove already mapped data.&lt;/p&gt;
&lt;p&gt;Finally we need to wire our &lt;code&gt;profileLoader&lt;/code&gt; method and all our normalizers methods in the constructor:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;__construct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;parent&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;__construct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getDefaultLoadersMap&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getDefaultNormalizersMap&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getSupportedFields&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public function __construct(){  parent::__construct(    self::getDefaultLoadersMap(),    self::getDefaultNormalizersMap(),    self::getSupportedFields()  );}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The methods &lt;code&gt;self::getDefaultLoadersMap&lt;/code&gt; and &lt;code&gt;self::getDefaultNormalizersMap&lt;/code&gt; are convenience methods defined in the &lt;code&gt;LazyExtractor&lt;/code&gt; class that defines respectively a loaders map and a normalizers map that are good in most of the cases.&lt;/p&gt;
&lt;p&gt;That’s all. To see the complete class have a look &lt;a href=&quot;https://github.com/Oryzone/PHPoAuthUserData/blob/master/src/OAuth/UserData/Extractor/Instagram.php&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important note&lt;/strong&gt;: if you are willing to submit a pull request to integrate a new extractor be sure to follow &lt;a href=&quot;http://www.php-fig.org/psr/psr-2/&quot;&gt;PSR-2 code style&lt;/a&gt; and to add a dedicated test case. Have a look at the &lt;a href=&quot;https://github.com/Oryzone/PHPoAuthUserData/blob/master/tests/OAuth/Unit/UserData/Extractor/InstagramTest.php&quot;&gt;InstagramTest&lt;/a&gt; class to understand how to do it.&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/writing-a-new-extractor-for-php-oauth-user-data.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/writing-a-new-extractor-for-php-oauth-user-data.png" width="1200" height="630"/></media:content><category>library</category><category>php</category><category>oauth</category><category>instagram</category><category>github</category><author>Luciano Mammino</author><comments>https://loige.co/writing-a-new-extractor-for-php-oauth-user-data/#comments</comments><enclosure url="https://loige.co/og/writing-a-new-extractor-for-php-oauth-user-data.png" length="0" type="image/png"/></item><item><title>6 Rules of thumb to build blazing fast web server applications</title><link>https://loige.co/6-rules-of-thumb-to-build-blazing-fast-web-applications/</link><guid isPermaLink="true">https://loige.co/6-rules-of-thumb-to-build-blazing-fast-web-applications/</guid><description>This post highlights 6 important rules to keep in mind when developing performant web applications: avoid premature optimization, do the minimum required work, defer non-critical tasks, leverage caching, avoid N+1 queries, and design for horizontal scaling. Following these guidelines will help you write efficient code from the start and build apps ready to handle growth.</description><pubDate>Sat, 25 Jul 2015 18:57:00 GMT</pubDate><content:encoded>&lt;p&gt;In this post I will try to highlight some of the most common principles that you have to take under consideration when you want to achieve a great level of performance while building a web application (specifically on the backend part). I believe the concepts discussed here can be applied to any language and framework even if, due to my specific experience, I will mention some examples, design patterns, conventions and tools that are mostly used in the PHP world.&lt;/p&gt;
&lt;p&gt;You can read this article in other languages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Japanese&lt;/strong&gt; on &lt;strong&gt;POSTD&lt;/strong&gt;: &lt;a href=&quot;http://postd.cc/6-rules-of-thumb-to-build-blazing-fast-web-server-applications/&quot;&gt;高速な Web サーバアプリケーションを構築するための 6 つの経験則&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Italian&lt;/strong&gt; on &lt;strong&gt;HTML5 Today&lt;/strong&gt;: &lt;a href=&quot;http://html5today.it/tutorial/performance-6-regole-sviluppare-applicazioni-web/&quot;&gt;Performance: 6 regole per sviluppare applicazioni web&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;TLDR;&lt;/strong&gt; the basic rules are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#rule-1&quot;&gt;Rule 1&lt;/a&gt;. Avoid premature optimization&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#rule-2&quot;&gt;Rule 2&lt;/a&gt;. Do the minimum amount of work to solve the problem&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#rule-3&quot;&gt;Rule 3&lt;/a&gt;. Defer the work you don’t need to do immediately&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#rule-4&quot;&gt;Rule 4&lt;/a&gt;. Use cache when you can&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#rule-5&quot;&gt;Rule 5&lt;/a&gt;. Understand and avoid the N+1 query problem with relational databases&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#rule-6&quot;&gt;Rule 6&lt;/a&gt;. Prepare your app for horizontal scalability when possible&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;Your code should be fast as Flash&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;728&quot; height=&quot;250&quot; src=&quot;https://loige.co/_astro/flash-gordon-fast-code.uyNnuFYu_1lnvN4.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;a id=&quot;rule-1&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;rule-1-avoid-premature-optimization&quot;&gt;Rule 1: Avoid premature optimization&lt;/h2&gt;
&lt;p&gt;One of the most famous &lt;a href=&quot;http://www-cs-faculty.stanford.edu/~uno/&quot;&gt;Donald Knuth&lt;/a&gt;’s quotes says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“premature optimization is the root of all evil”
&lt;br&gt;&lt;br&gt;&lt;a href=&quot;https://twitter.com/home?status=%22Premature%20optimization%20is%20the%20root%20of%20all%20evil%22%20%E2%80%94D.Knuth%20%0A%0AWeb%20apps%20performance%20tips%20by%20%40loige%3A%20http%3A//bit.ly/1SaHIJY&quot; target=&quot;_blank&quot;&gt;&lt;i class=&quot;fa fa-twitter&quot;&gt;&lt;/i&gt; Tweet this&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Knuth’s noticed that a lot of software developers generally waste a huge amount of time thinking about performance of non-critical parts of the code they are writing. This very often happens because such developers don’t really know what are the critical parts of their code or the ones that need to be optimized more, so they start to worry about futile things like “&lt;em&gt;are double quoted strings slower than single quoted ones?&lt;/em&gt;”&lt;/p&gt;
&lt;p&gt;To avoid to fall into the premature optimization trap you should write the first version of your code without worrying much about performance. Then you can use a &lt;strong&gt;profiler&lt;/strong&gt; to instrument your code and see where the bottlenecks are. This way you can focus on improving only the parts that really need your attention.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: I want to make it clear that Knuth’s quote doesn’t mean that you don’t have to care about optimization at all and it’s not an excuse to write shitty code and then abandon it. I just intended it as an encouragement to learn how to “optimize smartly” and that’s the way you should read it as well.&lt;/p&gt;
&lt;p&gt;If you are working on the PHP land there are a loot of tools that you can easily adopt to profile your code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;http://xdebug.org/&quot;&gt;xdebug&lt;/a&gt;&lt;/strong&gt;: probably the most famous PHP debugger and profiler, it must be installed as a PHP extension and it’s easily integrable in most of the IDEs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/phacility/xhprof&quot;&gt;xhprof&lt;/a&gt;&lt;/strong&gt;: a function-level hierarchical profiler for PHP. It comes with a simple HTML based navigational interface and offers some cool diff capabilities to compare the performance of different versions of your code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://symfony.com/doc/current/cookbook/profiler/index.html&quot;&gt;Symfony profiler&lt;/a&gt;&lt;/strong&gt;: The Symfony profiler it’s a one of the best features of the Symfony framework. It allows you to inspect the execution time of every request, showcasing a nice timeline that allows you to easily understand which part of your code is the most time-consuming. It is automatically enabled in “development” mode and does not need any PHP extension to be installed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://symfony.com/doc/current/components/stopwatch.html&quot;&gt;The Stopwatch component&lt;/a&gt;&lt;/strong&gt;: It’s the low level library used in the Symfony profiler to measure the execution time of a piece of PHP code. It can be easily integrated in any PHP project and does not require any extension.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://blackfire.io/&quot;&gt;Blackfire.io&lt;/a&gt;&lt;/strong&gt;: a profiler optimized for PHP that offers a very nice web interface that allows you to understand visually what your code does and where the CPU spends most of its time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://tideways.io/&quot;&gt;Tideways&lt;/a&gt;&lt;/strong&gt;: a promising alternative to Blackfire, offers a lot of graphical tools (timeline, call graphs, etc.) to make it really easy to find bottlenecks. It’s meant to be run continuously (also in production).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to know more on this specific topic you can have a read at the following articles and papers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.ircmaxell.com/2011/08/on-optimization-in-php.html&quot;&gt;On optimization in PHP&lt;/a&gt; by Anthony Ferrara&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://ubiquity.acm.org/article.cfm?id=1513451&quot;&gt;The fallacy of premature optimization&lt;/a&gt; by Randall Hyde&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.c2.com/cgi/wiki?PrematureOptimization&quot;&gt;Premature optimization&lt;/a&gt; by Cunningham &amp;#x26; Cunningham, Inc&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a id=&quot;rule-2&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;rule-2-do-just-what-you-need-to&quot;&gt;Rule 2: Do just what you need to&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Joker meme I Just Do Things&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;500&quot; height=&quot;269&quot; src=&quot;https://loige.co/_astro/i-just-do-things-joker-meme.B2Pvqtpv_Z2uuzIY.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Very often your code does more things than it’s required to do to produce the expected output. This is especially true if you are using complex libraries and frameworks in your code. Just to give you some examples you might load classes that you’ll never use, you might open a database connection or read a file for every request even when these resources are not needed to generate the output for a specific request.&lt;/p&gt;
&lt;p&gt;There are a number of design patterns and techniques that can help you to avoid these situations and achieve better performances.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Autoloading&lt;/strong&gt;: it’s a &lt;a href=&quot;http://php.net/manual/en/language.oop5.autoload.php&quot;&gt;PHP feature&lt;/a&gt; that allows you to require the file containing the definition of a class only when you are about to use that class (instantiation, static method call, access to a constant, etc.). This way you should not worry about which files to include in your script, but just to use that classes that you need. Autoloading will do the rest for you. Configuring autoloading has been a little bit complex in the past, especially because every library used its own conventions, but today thanks to the &lt;a href=&quot;http://www.php-fig.org/psr/psr-0/&quot;&gt;PSR-0&lt;/a&gt; and &lt;a href=&quot;http://www.php-fig.org/psr/psr-4/&quot;&gt;PSR-4&lt;/a&gt; standards and tools like &lt;em&gt;Composer&lt;/em&gt; it is a piece of cake to use autoloading.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dependency Injection&lt;/strong&gt;: it’s a very common &lt;a href=&quot;https://en.wikipedia.org/wiki/Dependency_injection&quot;&gt;design pattern&lt;/a&gt; in the Java world that in the last years has got a lot of traction even in the PHP world thanks also to the effort of frameworks like Symfony, Zend and Laravel that use and advocate it widely. Basically it allows to inject components through the constructor or a setter method. This has the effect of forcing the developer to think in terms of dependencies and to create small isolated components focused on doing just one thing and do it well.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lazy Loading&lt;/strong&gt;: another important &lt;a href=&quot;https://en.wikipedia.org/wiki/Lazy_loading&quot;&gt;design pattern&lt;/a&gt; used to defer initialization of an object until the point at which it is needed. It’s mostly used with objects that deals with heavy resources like database connections or file based data sources.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a id=&quot;rule-3&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;rule-3-mama-ill-do-it-tomorrow&quot;&gt;Rule 3: Mama, I’ll do it tomorrow!&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Tomorrow definition mystical land for human productivity&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;415&quot; height=&quot;390&quot; src=&quot;https://loige.co/_astro/i-ll-do-it-tomorrow-meme.3JNMxJo1_2qfhg4.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;How many times do you needed to send an email to a user after he/she triggered a specific event in your web app (e.g. password changed or order completed)? How many times you needed to resize an image after the user uploaded it? Well it’s quite common to do these “heavy” operations before sending a success message to the user. To put it another way, our users expects to see some message in their browsers as soon as possible and we need to ensure that any additional task (not directly related with creating that message) should be deferred.
The most common way to do that is to use &lt;a href=&quot;https://en.wikipedia.org/wiki/Job_queue&quot;&gt;job queues&lt;/a&gt;, which means that you have to store the minimum amount of data needed to perform the deferred task into a queue of some kind (e.g. a database, a message broker) and forget about it. You have to get back immediately to your main task: generating the output for the user! There will be some kind of worker in place with the goal to read from the queue periodically and perform the deferred job (e.g. sending the e-mail or generating the image thumbnails).&lt;/p&gt;
&lt;p&gt;A simple queue system can be easily done with any kind of data store (very often Redis or MongoDB are used) or a message broker like RabbitMQ or ActiveMQ. There are also a lot of implementation already done for the PHP world:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/chrisboulton/php-resque&quot;&gt;Resque&lt;/a&gt;: A PHP queue library that uses Redis as data store.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://laravel.com/docs/5.1/queues&quot;&gt;Laravel Queues&lt;/a&gt;: the Laravel/Lumen out-of-the-box solution to defer jobs using queues and workers. It can be configured to use different data stores.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://gearman.org/&quot;&gt;Gearman&lt;/a&gt;: A generic job server that supports the wide majority of languages (PHP among the others).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://kr.github.io/beanstalkd/&quot;&gt;Beanstalkd&lt;/a&gt;: Another fast work queue with client libraries for the most common languages (Ruby, PHP, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a id=&quot;rule-4&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;rule-4-gotta-cache-em-all&quot;&gt;Rule 4: Gotta cache ‘em all!&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Comic strip about the cloud and the cache&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;740&quot; height=&quot;236&quot; src=&quot;https://loige.co/_astro/cache-joke-comic-the-cloud.Dn_hExJs_1Cv7ON.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Nowadays web apps are really complex pieces of code. In order to generate a response to every request we generally do a lot of things: connect to one or more database, call external APIs, read configuration files, compute and aggregate data, serialize the results into some parseable format (Xml, Json, etc.) or render it with a template engine into a wonderful HTML page.
Using a naive approach we can do that for every request that we get, our servers will never get bored to do repetitive tasks.&lt;/p&gt;
&lt;p&gt;But there’s a smarter (and faster) way to do repetitive tasks, avoiding to calculate the same results again and again: enter “&lt;em&gt;the cache&lt;/em&gt;”!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Cache, which is pronounced “cash” (not “catch” or “cashay”), stores recently used information so that it can be quickly accessed at a later time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Cache is used widely in computer science and you can find it pretty much everywhere. For example the RAM itself can be considered as a way to cache the code of running programs to avoid the CPU to read the (slow) hard disk sparsely millions and millions of times.&lt;/p&gt;
&lt;p&gt;In general with web programming we can focus on several different &lt;strong&gt;levels of cache&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Byte Code Cache&lt;/strong&gt;: it’s a common feature of many interpreted languages (PHP, Python, Ruby, etc.) and it allows to avoid to interpretate source code files again and again if they are not changed since the last time. Some languages have this feature integrated in the core (Python), others like PHP needs to have it as an extension and several extensions exists for this sake: &lt;a href=&quot;http://php.net/manual/en/book.apc.php&quot;&gt;APC&lt;/a&gt;, &lt;a href=&quot;http://eaccelerator.net/&quot;&gt;eAccelerator&lt;/a&gt;, &lt;a href=&quot;http://xcache.lighttpd.net/&quot;&gt;Xcache&lt;/a&gt;. Since PHP 5.5 we can use the &lt;a href=&quot;http://php.net/manual/en/book.opcache.php&quot;&gt;Opcache extension&lt;/a&gt; which has been integrated in the core.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Application Cache&lt;/strong&gt;: to not be confused with HTML5 Application cache, is the cache logic that regards your specific application and it’s probably the most important in terms of performance. Are you computing the 1264575th number in the Fibonacci sequence over and over again in your app? Well put the result in a cache and avoid to recompute it every time. Or, to give a more realistic example, are you always making the same expensive queries to the database over and over again to render the front page of you app? Well cache the results of the queries (or even the output of the whole page when possible) and avoid to hit the database for every user request. In these cases it’s a good idea to use cache servers like &lt;a href=&quot;http://memcached.org/&quot;&gt;Memcached&lt;/a&gt;, &lt;a href=&quot;http://redis.io/&quot;&gt;Redis&lt;/a&gt; or &lt;a href=&quot;http://gibson-db.in/&quot;&gt;Gibson&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HTTP Cache&lt;/strong&gt;: Fetching data over the network is slow: a lot of round trips between the client and server are required and a lot of time is wasted before the browser is able to display the content. Wouldn’t it be useful to have ways to tell the browser to reuse content that he already downloaded?
Well, you can do that by using &lt;strong&gt;HTTP Cache headers&lt;/strong&gt; like &lt;code&gt;Etag&lt;/code&gt; and &lt;code&gt;Cache-control&lt;/code&gt;. This turns to be the cheapest way in terms of server resources to leverage cache (because everything is already in the browser and the server doesn’t get requests at all), you should only be sure to use it properly to avoid returning visitors to see stale content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Proxy Cache&lt;/strong&gt;: this technique refers to the usage of a dedicated server that receives all the HTTP traffic and it may have copies of the web pages requested by the users (often called &lt;strong&gt;Reverse proxy&lt;/strong&gt;). In these cases it returns the copy of the page directly without requiring the app server to re-elaborate the request. It generally keeps the copy of the data in memory and avoids many network round trips so it’s generally an out-of-the-box approach to speed up very trafficked web sites where the content doesn’t change too frequently. Famous proxy servers are &lt;a href=&quot;https://www.varnish-cache.org/&quot;&gt;Varnish&lt;/a&gt;, &lt;a href=&quot;http://nginx.org/&quot;&gt;Nginx&lt;/a&gt; and &lt;a href=&quot;http://www.squid-cache.org/&quot;&gt;Squid&lt;/a&gt;. Also &lt;a href=&quot;http://httpd.apache.org/&quot;&gt;Apache&lt;/a&gt; can be configured to act as a reverse proxy.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Anyway, once you got the concept of caching, it is really easy to adopt it. The issues arise when you need to understand whether something changed and the cached version of your data might not be relevant anymore. In such cases you need to delete the data on the cache to be sure it gets correctly recomputed the next it’s requested. This process is called “&lt;em&gt;cache invalidation&lt;/em&gt;” and it generally makes developers insane to the point that a very famous quote exists:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are only two hard things in Computer Science: &lt;strong&gt;cache invalidation&lt;/strong&gt; and naming things.&lt;/p&gt;
&lt;p&gt;— Phil Karlton
&lt;br&gt;&lt;br&gt;&lt;a href=&quot;https://twitter.com/home?status=There%20are%20only%202%20hard%20things%20in%20CS%3A%20cache%20invalidation%20and%20naming%20things%0A%E2%80%94Karlton%0AWeb%20apps%20performance%20tips%20by%20%40loige%20http%3A//bit.ly/1SaHIJY&quot; target=&quot;_blank&quot;&gt;&lt;i class=&quot;fa fa-twitter&quot;&gt;&lt;/i&gt; Tweet this&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you have been into software development for a while I’m quite sure that you already had chance to read it!&lt;/p&gt;
&lt;p&gt;There’s no silver bullet to make cache invalidation easy, it really depends from the architecture of your code and the requirements of your application. In general the less caching layers you have the better: always avoid to add complexity!&lt;/p&gt;
&lt;p&gt;Here follows some articles that might be interesting to know more about caching for web applications:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://docforge.com/wiki/Web_application/Caching&quot;&gt;Web application caching&lt;/a&gt; by DocForge&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tideways.io/profiler/blog/fine-tune-your-opcache-configuration-to-avoid-caching-suprises&quot;&gt;Fine tune your Opcache configuration to avoid caching surprises&lt;/a&gt; by Tideways blog&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.mobify.com/blog/beginners-guide-to-http-cache-headers/&quot;&gt;Beginners guide to HTTP cache headers&lt;/a&gt; by Mobify&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching&quot;&gt;HTTP Caching, optimizing content efficiency&lt;/a&gt; by Google&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://symfony.com/it/doc/current/book/http_cache.html&quot;&gt;Using Http headers with Symfony&lt;/a&gt; by Symfony&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nginx.com/resources/glossary/reverse-proxy-server/&quot;&gt;What is a reverse proxy server&lt;/a&gt; by Nginx&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://laravel.com/docs/5.1/cache&quot;&gt;Laravel cache&lt;/a&gt; by Laravel&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a id=&quot;rule-5&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;rule-5-avoid-the-damn-n1-query-problem&quot;&gt;Rule 5: Avoid the damn N+1 Query Problem&lt;/h2&gt;
&lt;p&gt;The “&lt;em&gt;N+1 Query Problem&lt;/em&gt;” is a very common anti-pattern unintentionally used especially when dealing with relational databases. Basically it reads N record from the database by generating N+1 queries (one to read the n IDs and 1 for every record). Take a look at the following piece of code to have a real case (well… almost real) example:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;php&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getUsers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//... retrieve the users from the database (1 query)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$users&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;loadLastLoginsForUsers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$users&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$users&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; as &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$lastLogins&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = ... &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// load the last logins for the user (1 query, executed n times)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$user&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;setLastLogins&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$lastLogins&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$users&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$users&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getUsers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;loadLastLoginsForUsers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$users&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;?phpfunction getUsers() {  //... retrieve the users from the database (1 query)  return $users;}function loadLastLoginsForUsers($users) {  foreach ($users as $user) {    $lastLogins = ... // load the last logins for the user (1 query, executed n times)    $user-&gt;setLastLogins($lastLogins);  }  return $users;}$users = getUsers();loadLastLoginsForUsers($users);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The given piece of code loads a list of users at first and then, for every user, it loads his last login times from the database. This code produces the following N+1 queries:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Users; &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;-- ids: 1, 2, 3, 4, 5, 6...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; * &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Logins &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; user_id = &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; * &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Logins &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; user_id = &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; * &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Logins &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; user_id = &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; * &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Logins &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; user_id = &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; * &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Logins &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; user_id = &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; * &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Logins &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; user_id = &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;-- ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;SELECT id FROM Users; -- ids: 1, 2, 3, 4, 5, 6...SELECT * FROM Logins WHERE user_id = 1;SELECT * FROM Logins WHERE user_id = 2;SELECT * FROM Logins WHERE user_id = 3;SELECT * FROM Logins WHERE user_id = 4;SELECT * FROM Logins WHERE user_id = 5;SELECT * FROM Logins WHERE user_id = 6;-- ...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That’s obviously inefficient and it happens quite often with “has many” relationships in databases, especially when you are using some kind of magic ORM and you don’t exactly know what it is doing out of the box (and probably you haven’t configured it properly).&lt;/p&gt;
&lt;p&gt;In general you can solve this problem by producing a query like the following:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; id &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Users; &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;-- ids: 1, 2, 3, 4, 5, 6...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; * &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Logins &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; user_id &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;IN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, ...);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;SELECT id FROM Users; -- ids: 1, 2, 3, 4, 5, 6...SELECT * FROM Logins WHERE user_id IN (1, 2, 3, 4, 5, 6, ...);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;or by using the &lt;code&gt;JOIN&lt;/code&gt; syntax where possible.&lt;/p&gt;
&lt;p&gt;This problem can be only addressed when you are in control of your SQL queries or if you have a clear understanding of the ORM library you are using (if you are using one). Anyway keep it in mind and be sure you don’t fall in the N+1 queries trap, especially when you deal with large datasets. Many PHP profilers allows you to inspect the generated queries for every page request, they can be very useful companion to understand if you are doing things properly in terms of avoiding the N+1 queries problem.&lt;/p&gt;
&lt;p&gt;On a side note, speaking of databases, be sure to keep a single connection open to your data source and to not reconnect for every query.&lt;/p&gt;
&lt;p&gt;Don’t expect this to be exhaustive. This problem is very broad and it has a lot of other important case to analyze, so if you want to know more about it have a look at the following articles and books:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/&quot;&gt;Performance: N+1 Query Problem&lt;/a&gt; by Phabricator&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://use-the-index-luke.com/sql/join/nested-loops-join-n1-problem&quot;&gt;Nested Loops&lt;/a&gt; by Use the Index, Luke&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://laravel.com/docs/5.0/eloquent#eager-loading&quot;&gt;Laravel’s Eloquent ORM Eager Loading&lt;/a&gt; by Laravel&lt;/li&gt;
&lt;li&gt;Book &lt;a href=&quot;https://leanpub.com/sn1php&quot;&gt;Solving The N+1 Problem In PHP&lt;/a&gt; by Paul M. Jones&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a id=&quot;rule-6&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;rule-6-scale-horizontally&quot;&gt;Rule 6: Scale… horizontally!&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Horizontal scalability is hard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;858&quot; height=&quot;309&quot; src=&quot;https://loige.co/_astro/web-apps-explodes-like-a-baloon-scalability-comic.w6z57Tv5_Z23cmwE.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;“Scalability” is not exactly the same thing of “performance”, but the two things are tightly intertwined.
To give you my personal definition, “scalability” is the ability of a system to adapt and remain functional without noticeable performance issues when the number of users (and requests) grows.&lt;/p&gt;
&lt;p&gt;It’s a very complex and broad topic and I don’t want to get into the details here. But for the sake of performance it’s worth to understand and keep in mind some simple things that you can do to be sure your app can be easily scaled horizontally. Horizontal scaling is a particular scaling strategy in which you add more machines to the cluster where your app is deployed. This way the load is split among all the machines and thus the whole system can remain performant even when there are a lot of simultaneous requests.&lt;/p&gt;
&lt;p&gt;The two major problems to take in consideration when preparing for horizontal scaling are user sessions and user files consistency.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sessions&lt;/strong&gt;: quite often (especially in PHP applications) user session data is stored on the local filesystem where the app is deployed. Using this strategy is not only slower but it will not work if you have two machines to handle the requests (the session data stored in one machine will be different than the one stored in the other). A better solution is to use some kind of database to store the user session data. Most of the frameworks easily allows you to do that with just few lines of configuration. At the beginning, when your app is small and it’s not so popular, you can install your favourite session storage platform in the same machine of your web sever. Than when you will need to scale your architecture you can easily move the session storage into a separate machine and connect all your web machines to it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User files consistency&lt;/strong&gt;: Same problem of sessions happens when users can store files within your app. In these cases you need to be sure that whatever is the web server they end up with they are able to see their files. So you need to keep the files into a dedicated storage (like &lt;a href=&quot;http://aws.amazon.com/s3/&quot;&gt;Amazon S3&lt;/a&gt; or &lt;a href=&quot;http://www.rackspace.com/cloud/files&quot;&gt;Rackspace Cloudfiles&lt;/a&gt;). Otherwise you can keep the files locally on the machines but you need to find a way to keep them synchronized within all the machines of the cluster. In this case you can use &lt;a href=&quot;https://en.wikipedia.org/wiki/Network_File_System&quot;&gt;NFS&lt;/a&gt; or &lt;a href=&quot;http://www.gluster.org/&quot;&gt;GlusterFS&lt;/a&gt; to create a shared filesystem.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s a list of other interesting resources to know more about scalable web applications:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://inviqa.com/blog/horizontally-scalable-web-applications/&quot;&gt;Horizontally scalable web applications&lt;/a&gt; by Inviqa&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.digitalocean.com/company/blog/horizontally-scaling-php-applications/&quot;&gt;Horizontally Scaling PHP Applications: A Practical Overview&lt;/a&gt; by Digital Ocean&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.openshift.com/best-practices-for-horizontal-application-scaling/&quot;&gt;Best Practices For Horizontal Application Scaling&lt;/a&gt; by OpenShift&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.aosabook.org/en/distsys.html&quot;&gt;Scalable Web Architecture and Distributed Systems&lt;/a&gt; by Kate Matsudaira&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://highscalability.com/blog/2014/3/17/intuitively-showing-how-to-scale-a-web-application-using-a-c.html&quot;&gt;Intuitively Showing How To Scale A Web Application Using A Coffee Shop As An Example&lt;/a&gt; by HighScalability&lt;/li&gt;
&lt;li&gt;Book &lt;a href=&quot;http://theartofscalability.com/&quot;&gt;The art of scalability&lt;/a&gt; by Martin Abbot and Michael Fisher&lt;/li&gt;
&lt;li&gt;Slides &lt;a href=&quot;http://www.slideshare.net/davemitz/7-stages-of-scaling-web-applications&quot;&gt;7 Stages of scaling web applications&lt;/a&gt; by Rackspace&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;I really hope this long post has been useful for you. I just wanted to give you an idea of what are the general concerns to take in mind when you start to write an app that should take performance under consideration. As I said in the first rule, don’t fall into the trap of premature optimization and just focus on writing the right code for the right job. Anyway if you have this points clear in your mind you will almost automatically think about good solutions to achieve a good level of performance and scalability from the very first versions of your app and you can also make some smart architectural decisions from the very beginning.&lt;/p&gt;
&lt;p&gt;In case you are an experienced web developer let me know if I forgot to mention any important rule and, if you commonly follow these rules, what you think about them.&lt;/p&gt;
&lt;p&gt;I hope some great discussion will start from the comments here.&lt;/p&gt;
&lt;p&gt;Thanks for taking your time to read this post.&lt;/p&gt;
&lt;p&gt;Until next time!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/6-rules-of-thumb-to-build-blazing-fast-web-applications.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/6-rules-of-thumb-to-build-blazing-fast-web-applications.png" width="1200" height="630"/></media:content><category>php</category><category>symfony</category><category>laravel</category><category>performance</category><category>scalability</category><author>Luciano Mammino</author><comments>https://loige.co/6-rules-of-thumb-to-build-blazing-fast-web-applications/#comments</comments><enclosure url="https://loige.co/og/6-rules-of-thumb-to-build-blazing-fast-web-applications.png" length="0" type="image/png"/></item><item><title>Write a console application using Symfony and Pimple</title><link>https://loige.co/write-a-console-application-using-symfony-and-pimple/</link><guid isPermaLink="true">https://loige.co/write-a-console-application-using-symfony-and-pimple/</guid><description>This article shows how to build a simple command line application using the Symfony Console component and Pimple dependency injection container. It provides a step-by-step guide on structuring the code, defining services, configuring parameters and wiring everything together to create a executable console app.</description><pubDate>Sat, 15 Mar 2014 02:16:20 GMT</pubDate><content:encoded>&lt;p&gt;In this article I will show you how to set up a stand alone command line application by using the &lt;a href=&quot;https://github.com/symfony/console&quot;&gt;Symfony Console component&lt;/a&gt; and &lt;a href=&quot;http://pimple.sensiolabs.org/&quot;&gt;Pimple&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Sample command line app&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;841&quot; height=&quot;301&quot; src=&quot;https://loige.co/_astro/Screenshot_from_2014_03_15_03_19_53.CYihyoAR_5rNuc.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Writing console commands for Symfony (full stack framework) is easy and enjoyable. It helps a lot when you need to handle particular collateral tasks that are needed, in a way or another, to make your website running (processing and crunching data, make async requests, create reports, etc.).&lt;/p&gt;
&lt;p&gt;Anyway I discovered that writing stand alone command line applications using only the &lt;a href=&quot;https://github.com/symfony/console&quot;&gt;Symfony/Console&lt;/a&gt; component is a lot more easy and enjoyable and that a lot of famous command line applications uses it (&lt;a href=&quot;https://getcomposer.org/&quot;&gt;Composer&lt;/a&gt; and &lt;a href=&quot;http://laravel.com/docs/commands&quot;&gt;Laravel/Artisan&lt;/a&gt; just to name a few). Furthermore by using Symfony I became a great fan of the &lt;em&gt;Dependency Injection&lt;/em&gt; and &lt;em&gt;Inversion of Control (IoC)&lt;/em&gt; &lt;a href=&quot;http://martinfowler.com/articles/injection.html&quot;&gt;design pattern&lt;/a&gt; and, as my dependencies started to grow, I wanted to put some sort of &lt;em&gt;container&lt;/em&gt; in my command line apps. I decided to go with &lt;a href=&quot;http://pimple.sensiolabs.org/&quot;&gt;Pimple&lt;/a&gt;: a really simple dependency injection container written by &lt;a href=&quot;http://fabien.potencier.org/&quot;&gt;Fabien Potencier&lt;/a&gt;, the notorious head behind the Symfony framework and Sensio.&lt;/p&gt;
&lt;h2 id=&quot;lets-start&quot;&gt;Let’s start&lt;/h2&gt;
&lt;p&gt;I will demonstrate my approach by creating a simple “hello &lt;em&gt;$name&lt;/em&gt;” command line application that will be able to count how many times you greet someone. You can find the whole code in a dedicated &lt;a href=&quot;https://github.com/lmammino/SymfonyConsolePimple&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So we will be able to run&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;app/console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;greet&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;Alice&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;app/console greet Alice&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;and it will print out&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Hello Alice&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;(First time!)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Hello Alice(First time!)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Yes, intentionally simple! ;)&lt;/p&gt;
&lt;p&gt;Let’s start by creating our &lt;em&gt;composer.json&lt;/em&gt; file. We will need the Symfony console and the Pimple packages. We also include the Symfony Yaml component as we will store data in a yaml file (obviously we could have been using json but I believe yaml is cooler :P).&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;lmammino/symfony-console-pimple&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;A sample Symfony Console app using Pimple&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;require&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;symfony/console&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;dev-master&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;pimple/pimple&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;dev-master&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;symfony/yaml&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;dev-master&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;license&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;MIT&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;authors&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Luciano Mammino&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;lmammino@oryzone.com&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;autoload&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;psr-4&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;LMammino&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ConsoleApp&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;src/&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{  &amp;#x22;name&amp;#x22;: &amp;#x22;lmammino/symfony-console-pimple&amp;#x22;,  &amp;#x22;description&amp;#x22;: &amp;#x22;A sample Symfony Console app using Pimple&amp;#x22;,  &amp;#x22;require&amp;#x22;: {    &amp;#x22;symfony/console&amp;#x22;: &amp;#x22;dev-master&amp;#x22;,    &amp;#x22;pimple/pimple&amp;#x22;: &amp;#x22;dev-master&amp;#x22;,    &amp;#x22;symfony/yaml&amp;#x22;: &amp;#x22;dev-master&amp;#x22;  },  &amp;#x22;license&amp;#x22;: &amp;#x22;MIT&amp;#x22;,  &amp;#x22;authors&amp;#x22;: [    {      &amp;#x22;name&amp;#x22;: &amp;#x22;Luciano Mammino&amp;#x22;,      &amp;#x22;email&amp;#x22;: &amp;#x22;lmammino@oryzone.com&amp;#x22;    }  ],  &amp;#x22;autoload&amp;#x22;: {    &amp;#x22;psr-4&amp;#x22;: {      &amp;#x22;LMammino\\ConsoleApp\\&amp;#x22;: &amp;#x22;src/&amp;#x22;    }  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Yes, let’s run &lt;code&gt;composer update&lt;/code&gt; to download all the libraries.&lt;/p&gt;
&lt;h2 id=&quot;folder-structure&quot;&gt;Folder structure&lt;/h2&gt;
&lt;p&gt;Let’s structure our code. We want to separate application and configuration code from the main source code. So we will end up with the following folder structure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;app&lt;/li&gt;
&lt;li&gt;src&lt;/li&gt;
&lt;li&gt;vendors&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;strong&gt;app&lt;/strong&gt; folder will contain our console executable file, a bootstrap file and a config folder. We will get into the details in a while.&lt;/p&gt;
&lt;h2 id=&quot;the-greeter-service&quot;&gt;The Greeter service&lt;/h2&gt;
&lt;p&gt;Let’s just define our core service by Writing the &lt;code&gt;Greeter&lt;/code&gt; class. This class defines the business logic of our greeting application.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;php&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;LMammino\ConsoleApp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Symfony\Component\Yaml\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Yaml&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Greeter&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;@var&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; $file&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$file&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;@var&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; $greetings&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$greetings&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* Constructor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;@param&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; $file&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;__construct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$file&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;file&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$file&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;file_exists&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$file&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;greetings&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Yaml&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;file_get_contents&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$file&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;greetings&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* Destructor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;__destruct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;file_put_contents&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;file&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Yaml&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;dump&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;greetings&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* Builds the greeting for someone (you can yell on it if you want!)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;@param&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; $name&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;@param&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;   $yell wanna yell?&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;@return&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;string&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;greet&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$yell&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$output&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;sprintf&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Hello %s&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$yell&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$output&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;strtoupper&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$output&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;strtolower&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (!&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;isset&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;greetings&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;])) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;greetings&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] = &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;greetings&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]++;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$output&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* Will tell you how many times you greet someone&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;@param&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; $name&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;@return&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;int&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;countGreetings&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;strtolower&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (!&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;isset&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;greetings&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;])) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;greetings&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;?phpnamespace LMammino\ConsoleApp;use Symfony\Component\Yaml\Yaml;class Greeter{    /**     * @var string $file     */    protected $file;    /**     * @var array $greetings     */    protected $greetings;    /**     * Constructor     *     * @param string $file     */    public function __construct($file)    {        $this-&gt;file = $file;        if (file_exists($file)) {            $this-&gt;greetings = Yaml::parse(file_get_contents($file));        } else {            $this-&gt;greetings = array();        }    }    /**     * Destructor     */    public function __destruct()    {        file_put_contents($this-&gt;file, Yaml::dump($this-&gt;greetings));    }    /**     * Builds the greeting for someone (you can yell on it if you want!)     *     * @param  string $name     * @param  bool   $yell wanna yell?     * @return string     */    public function greet($name, $yell = false)    {        $output = sprintf(&amp;#x27;Hello %s&amp;#x27;, $name);        if ($yell) {            $output = strtoupper($output);        }        $name = strtolower($name);        if (!isset($this-&gt;greetings[$name])) {            $this-&gt;greetings[$name] = 1;        } else {            $this-&gt;greetings[$name]++;        }        return $output;    }    /**     * Will tell you how many times you greet someone     *     * @param  string $name     * @return int     */    public function countGreetings($name)    {        $name = strtolower($name);        if (!isset($this-&gt;greetings[$name])) {            return 0;        }        return $this-&gt;greetings[$name];    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The class is really simple. The main methods are &lt;code&gt;greet&lt;/code&gt; and &lt;code&gt;countGreetings&lt;/code&gt; that allows you to build the greet string for someone and to count how many times you have greet someone.&lt;/p&gt;
&lt;p&gt;Note that this class needs to know on costruction which file to use to read and store the greetings count. This will be something we will configure through Pimple as a container parameter.&lt;/p&gt;
&lt;h2 id=&quot;the-greetcommand&quot;&gt;The GreetCommand&lt;/h2&gt;
&lt;p&gt;Now we have a service with the main business logic, let’s just write a Symfony command to run it:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;php&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;LMammino\ConsoleApp\Command&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; LMammino\ConsoleApp\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Greeter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Symfony\Component\Console\Command\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Command&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Symfony\Component\Console\Input\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;InputArgument&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Symfony\Component\Console\Input\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;InputInterface&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Symfony\Component\Console\Input\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;InputOption&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Symfony\Component\Console\Output\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;OutputInterface&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;GreetCommand&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Command&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;@var&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; \LMammino\ConsoleApp\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01;--1fs:italic&quot;&gt;Greeter&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; $greeter&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$greeter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* Constructor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;@param&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01;--1fs:italic&quot;&gt;Greeter&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; $greeter&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;__construct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Greeter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$greeter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;parent&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;__construct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;greeter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$greeter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* {&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;@inheritDoc&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;configure&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;setName&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;greet&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;setDescription&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Greet someone&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;addArgument&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;name&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;InputArgument&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;OPTIONAL&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;The name of the one you want to greet&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;World&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;addOption&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;yell&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Y&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;InputOption&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;VALUE_NONE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;If set will scream out the greeting. Use with caution!&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* {&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4;--1fs:italic&quot;&gt;@inheritDoc&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;execute&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;InputInterface&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$input&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;OutputInterface&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$output&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$input&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getArgument&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;name&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$yell&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$input&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getOption&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;yell&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$output&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;writeln&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;greeter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;greet&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$yell&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; === (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$count&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;greeter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;countGreetings&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;))) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$output&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;writeln&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;(First time!)&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$output&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;writeln&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;sprintf&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;(%d times)&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$count&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;?phpnamespace LMammino\ConsoleApp\Command;use LMammino\ConsoleApp\Greeter;use Symfony\Component\Console\Command\Command;use Symfony\Component\Console\Input\InputArgument;use Symfony\Component\Console\Input\InputInterface;use Symfony\Component\Console\Input\InputOption;use Symfony\Component\Console\Output\OutputInterface;class GreetCommand extends Command{    /**     * @var \LMammino\ConsoleApp\Greeter $greeter     */    protected $greeter;    /**     * Constructor     *     * @param Greeter $greeter     */    public function __construct(Greeter $greeter)    {        parent::__construct();        $this-&gt;greeter = $greeter;    }    /**     * {@inheritDoc}     */    protected function configure()    {        $this-&gt;setName(&amp;#x27;greet&amp;#x27;)            -&gt;setDescription(&amp;#x27;Greet someone&amp;#x27;)            -&gt;addArgument(&amp;#x27;name&amp;#x27;, InputArgument::OPTIONAL, &amp;#x27;The name of the one you want to greet&amp;#x27;, &amp;#x27;World&amp;#x27;)            -&gt;addOption(&amp;#x27;yell&amp;#x27;, &amp;#x27;Y&amp;#x27;, InputOption::VALUE_NONE, &amp;#x27;If set will scream out the greeting. Use with caution!&amp;#x27;);    }    /**     * {@inheritDoc}     */    protected function execute(InputInterface $input, OutputInterface $output)    {        $name = $input-&gt;getArgument(&amp;#x27;name&amp;#x27;);        $yell = $input-&gt;getOption(&amp;#x27;yell&amp;#x27;);        $output-&gt;writeln($this-&gt;greeter-&gt;greet($name, $yell));        if (1 === ($count = $this-&gt;greeter-&gt;countGreetings($name))) {            $output-&gt;writeln(&amp;#x27;(First time!)&amp;#x27;);        } else {            $output-&gt;writeln(sprintf(&amp;#x27;(%d times)&amp;#x27;, $count));        }    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The command is totally self explainatory! It just defines the &lt;em&gt;greet&lt;/em&gt; command offering a &lt;em&gt;name&lt;/em&gt; argument and a &lt;em&gt;yell&lt;/em&gt; option (both optional). The point here is that our command has a dependency on the &lt;code&gt;Greeter&lt;/code&gt; class we wrote before. So we need to pass it on construction (or we need to configure our Pimple container to do so).&lt;/p&gt;
&lt;h2 id=&quot;ladies-and-gents-the-pimple-container&quot;&gt;Ladies and gents, the Pimple container!&lt;/h2&gt;
&lt;p&gt;Finally it’s time to write our Pimple container. Before getting to the code let’s recap things a bit.
We have a parameter (the name of the greetings count file) and two services (the &lt;code&gt;Greeter&lt;/code&gt; service and the &lt;code&gt;GreetCommand&lt;/code&gt;).
We will create a &lt;code&gt;app/config/container.php&lt;/code&gt; file to define our parameters and services with Pimple:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;php&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Pimple&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;parameters&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] = &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;greetings.file&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;greetings.yaml&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;greeter&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; \LMammino\ConsoleApp\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Greeter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;parameters&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;greetings.file&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;command.greet&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; \LMammino\ConsoleApp\Command\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;GreetCommand&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;greeter&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;commands&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;command.greet&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;application&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$application&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; \Symfony\Component\Console\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Application&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$application&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;addCommands&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;commands&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$application&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;?php$c = new Pimple();$c[&amp;#x27;parameters&amp;#x27;] = array(    &amp;#x27;greetings.file&amp;#x27; =&gt; &amp;#x27;greetings.yaml&amp;#x27;);$c[&amp;#x27;greeter&amp;#x27;] = function($c) {    return new \LMammino\ConsoleApp\Greeter($c[&amp;#x27;parameters&amp;#x27;][&amp;#x27;greetings.file&amp;#x27;]);};$c[&amp;#x27;command.greet&amp;#x27;] = function($c) {    return new \LMammino\ConsoleApp\Command\GreetCommand($c[&amp;#x27;greeter&amp;#x27;]);};$c[&amp;#x27;commands&amp;#x27;] = function($c) {    return array(        $c[&amp;#x27;command.greet&amp;#x27;]    );};$c[&amp;#x27;application&amp;#x27;] = function($c) {    $application = new \Symfony\Component\Console\Application();    $application-&gt;addCommands($c[&amp;#x27;commands&amp;#x27;]);    return $application;};return $c;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If you were not familiar with Pimple you should have noticed the simple syntax of this container. We just need to create a Pimple instance and it acts like an array. In this “array” we put parameters as simple data (scalar or array values) and service definitions as functions that return instantiated services.
Let’s check our definitions one by one:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$c[&apos;parameters&apos;]&lt;/code&gt; contains the applications parameters (in a more complex application with a lot of parameters you can load the values from an external configuration file)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$c[&apos;greeter&apos;]&lt;/code&gt; defines the construction of our &lt;code&gt;Greeter&lt;/code&gt; service&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$c[&apos;command.greet&apos;]&lt;/code&gt; defines the construction of our &lt;em&gt;greet&lt;/em&gt; command&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$c[&apos;commands&apos;]&lt;/code&gt; is an helper definition that returns an array with all the commands that we want to add in our application&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$c[&apos;application&apos;]&lt;/code&gt; defines the creation of our command line application&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ok, we are almost done. We just need to write our bootstrap file and our console executable file.&lt;/p&gt;
&lt;h2 id=&quot;the-bootstrap-file&quot;&gt;The bootstrap file&lt;/h2&gt;
&lt;p&gt;The file &lt;code&gt;app/bootstrap.php&lt;/code&gt; is used to load the composer autoloader class and our container:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;php&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;set_time_limit&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;__DIR__&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/../vendor/autoload.php&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$container&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;__DIR__&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/config/container.php&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;?phpset_time_limit(0);require __DIR__ . &amp;#x27;/../vendor/autoload.php&amp;#x27;;$container = require(__DIR__ . &amp;#x27;/config/container.php&amp;#x27;);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;set_time_limit(0)&lt;/code&gt; ensures that our script will not be killed after a certain amount of seconds (if your &lt;em&gt;php.ini&lt;/em&gt; wants so). It’s almost useless in this particular case (our command will run in a few milliseconds) but adding it in Php command line applications is a good practice (especially when you have to deal with long running tasks).&lt;/p&gt;
&lt;h2 id=&quot;the-executable-console-file&quot;&gt;The executable console file&lt;/h2&gt;
&lt;p&gt;The last step needed to make our application executable is to write the &lt;code&gt;app/console&lt;/code&gt; file. This is a php file that can be executed from the command line (you need to &lt;code&gt;chmod +x&lt;/code&gt; it).&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;#!/usr/bin/env php&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;php&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;__DIR__&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/bootstrap.php&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$application&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$container&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;application&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$application&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;#!/usr/bin/env php&lt;?phprequire __DIR__ . &amp;#x27;/bootstrap.php&amp;#x27;;$application = $container[&amp;#x27;application&amp;#x27;];$application-&gt;run();&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;By using a container it just need to load our “application” service and call &lt;code&gt;run()&lt;/code&gt; on it.&lt;/p&gt;
&lt;p&gt;Note that the first “&lt;a href=&quot;http://en.wikipedia.org/wiki/Shebang_%28Unix%29&quot;&gt;shebang&lt;/a&gt;” line (&lt;code&gt;#!/usr/bin/env php&lt;/code&gt;) allows us to run this file by calling &lt;code&gt;app/console&lt;/code&gt; (so that you can avoid to call the php interpreter explicitly).&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;This app is very simple and it will be easy to build even without adopting a container. Anyway I think this approach guarantees a good organization for your code and will became really useful when your command line application start to grow in terms of complexity.
I recently had to build a command line app that uses Doctrine and JMS/Serializer (plus several other dependecies). I can say that adopting a container like Pimple helped me a lot to keep things organized and services decoupled.&lt;/p&gt;
&lt;p&gt;Just to make a final recap I think this approach guarantees several benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write &lt;strong&gt;“container agnostic” commands&lt;/strong&gt; (they does not know the container, but have only the required dependencies injected)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Attach new commands from configuration&lt;/strong&gt;: you just need to add them to the &lt;code&gt;$container[&apos;commands&apos;]&lt;/code&gt; array&lt;/li&gt;
&lt;li&gt;Help you a lot to write &lt;strong&gt;thin commands&lt;/strong&gt; (yes, I think commands acts like controllers and they should be “thin” too), because you have a simple way to declare services and their dependencies and you are able to inject only the needed ones in every command&lt;/li&gt;
&lt;li&gt;Allow you to have &lt;strong&gt;parameters and configuration&lt;/strong&gt; (useful when you have to enstablish a connection with a database or use external resources that needs configuration such as an external API)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That should be all. Feel free to comment this post or to contribute to the &lt;a href=&quot;https://github.com/lmammino/SymfonyConsolePimple&quot;&gt;sample app repository&lt;/a&gt; if you feel that this approach can be tweaked.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt; (March 16, 2014):&lt;br&gt;
&lt;a href=&quot;https://twitter.com/javiereguiluz&quot;&gt;Javier Egiluz&lt;/a&gt;, great Symfony evangelist, pointed out that one of his command line applications, &lt;a href=&quot;http://easybook-project.org/&quot;&gt;easybook&lt;/a&gt;, uses the Symfony Console component in conjunction with Pimple. So if you want to have a look to a more complete and realistic (and complex :P) use case I really suggest you to have a look at the &lt;a href=&quot;https://github.com/javiereguiluz/easybook&quot;&gt;easybook code base&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Have a nice weekend!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/write-a-console-application-using-symfony-and-pimple.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/write-a-console-application-using-symfony-and-pimple.png" width="1200" height="630"/></media:content><category>php</category><category>symfony</category><category>console</category><category>pimple</category><author>Luciano Mammino</author><comments>https://loige.co/write-a-console-application-using-symfony-and-pimple/#comments</comments><enclosure url="https://loige.co/og/write-a-console-application-using-symfony-and-pimple.png" length="0" type="image/png"/></item><item><title>Simple echo server written in Go, dockerized!</title><link>https://loige.co/simple-echo-server-written-in-go-dockerized/</link><guid isPermaLink="true">https://loige.co/simple-echo-server-written-in-go-dockerized/</guid><description>By writing a Dockerfile we can containerize a simple Go echo server app. The Dockerfile installs Go, copies the server code, exposes the port, and defines the command to run the app. Building the Dockerfile produces an image that can be run as a container. The containerized Go app can then be easily distributed and run anywhere Docker is installed.</description><pubDate>Sun, 29 Jun 2014 14:43:56 GMT</pubDate><content:encoded>&lt;p&gt;In this post we will see how to write a (very) simple &lt;strong&gt;Go server app&lt;/strong&gt; and how to put it into a &lt;strong&gt;Docker container&lt;/strong&gt; and run it.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Dockerize a Go application&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;780&quot; height=&quot;439&quot; src=&quot;https://loige.co/_astro/dockerize-go-app.DGZGm_pE_1tYwgt.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: I’m an absolute beginner with both &lt;a href=&quot;http://golang.org&quot;&gt;Go&lt;/a&gt; and &lt;a href=&quot;https://docker.com&quot;&gt;Docker&lt;/a&gt; and this is just an experiment I did to start to explore this two interesting technologies. If you’ll find something weird or wrong you are &lt;strong&gt;very&lt;/strong&gt; encouraged to scream at me in the comments (&lt;a href=&quot;#disqus_thread&quot;&gt;Comments&lt;/a&gt;), I will be extremely thankful ;)&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;We are going to write a simple echo server in Go and then we will pack it into a Docker container for future execution/distribution.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;“Luciano, you are a PHP developer, why bothering with Go?”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Nice question! Well, there are at least two reasons for this choice:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Experimenting&lt;/strong&gt;! Yes Go seems to be the next cool thing in the field and I wanted to have an excuse to try it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simplicity&lt;/strong&gt;! Writing a server app in Go is just a matter of writing few lines of code in a file, so it’s an very simple scenario to test the integration with Docker.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For those who are not familiar with these two technologies I suggest give the official websites a shot (&lt;a href=&quot;https://docker.com&quot;&gt;Docker.com&lt;/a&gt; and &lt;a href=&quot;http://golang.org&quot;&gt;Golang.org&lt;/a&gt;) as I will not provide many specific details about them.
I assume you have both technologies installed on your machine. If you are using Windows or a Mac have a look at &lt;a href=&quot;https://github.com/boot2docker/boot2docker&quot;&gt;Boot2Docker&lt;/a&gt;, it will definitely make your life easier.&lt;/p&gt;
&lt;p&gt;Beware that Go on your local machine is needed only if you want to test the application before “dockerizing” it. We will put the Go runtime into the Docker container in the second part of the post and this way we will be able to execute it without having Go installed in our local machine (that’s infact the real advantage of using Docker).&lt;/p&gt;
&lt;h2 id=&quot;the-go-echo-server&quot;&gt;The Go echo server&lt;/h2&gt;
&lt;p&gt;Ok, first of all let’s write and test our server app. The app should open a socket and listen for TCP requests on a given port. Then when it receives some data it should reply by saying something like that &lt;em&gt;“Hi, I received your message! It was X bytes long and that’s what it said: XXX ! Honestly I have no clue about what to do with your messages, so Bye Bye!”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So let’s just write some code. The following script has been widely inspired by &lt;a href=&quot;https://coderwall.com/p/wohavg&quot;&gt;this one&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;server.go&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;package&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;main&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;fmt&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;net&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;os&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;strconv&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;bytes&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;CONN_HOST&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;CONN_PORT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;3333&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;CONN_TYPE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;tcp&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Listen for incoming connections.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;l&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; := &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;net&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Listen&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;CONN_TYPE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;:&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;CONN_PORT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; != &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Println&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Error listening:&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;os&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Exit&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Close the listener when the application closes.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;defer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;l&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Close&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Println&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Listening on &quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; + &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;CONN_HOST&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; + &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;:&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; + &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;CONN_PORT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Listen for an incoming connection.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;conn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; := &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;l&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Accept&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; != &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Println&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Error accepting: &quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;os&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Exit&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//logs an incoming message&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Printf&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Received message &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;%s&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt; -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;%s&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;conn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;RemoteAddr&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;conn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;LocalAddr&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Handle connections in a new goroutine.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;handleRequest&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;conn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Handles incoming requests.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;handleRequest&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;conn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;net&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Conn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Make a buffer to hold incoming data.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;buf&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; := &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;make&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;([]&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#A626A4&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1024&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Read the incoming connection into the buffer.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;reqLen&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; := &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;conn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Read&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;buf&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; != &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Println&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Error reading:&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Builds the message.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; := &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Hi, I received your message! It was &quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; += &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;strconv&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Itoa&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;reqLen&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; += &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot; bytes long and that&apos;s what it said: &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; := &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;bytes&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Index&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;buf&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, []&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#A626A4&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; += &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#A626A4&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;buf&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[:&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;])&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; += &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt; ! Honestly I have no clue about what to do with your messages, so Bye Bye!&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Write the message in the connection channel.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;conn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Write&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;([]&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#A626A4&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Close the connection when you&apos;re done with it.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;conn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Close&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;package mainimport (    &amp;#x22;fmt&amp;#x22;    &amp;#x22;net&amp;#x22;    &amp;#x22;os&amp;#x22;    &amp;#x22;strconv&amp;#x22;    &amp;#x22;bytes&amp;#x22;)const (    CONN_HOST = &amp;#x22;&amp;#x22;    CONN_PORT = &amp;#x22;3333&amp;#x22;    CONN_TYPE = &amp;#x22;tcp&amp;#x22;)func main() {    // Listen for incoming connections.    l, err := net.Listen(CONN_TYPE, &amp;#x22;:&amp;#x22;+CONN_PORT)    if err != nil {        fmt.Println(&amp;#x22;Error listening:&amp;#x22;, err.Error())        os.Exit(1)    }    // Close the listener when the application closes.    defer l.Close()    fmt.Println(&amp;#x22;Listening on &amp;#x22; + CONN_HOST + &amp;#x22;:&amp;#x22; + CONN_PORT)    for {        // Listen for an incoming connection.        conn, err := l.Accept()        if err != nil {            fmt.Println(&amp;#x22;Error accepting: &amp;#x22;, err.Error())            os.Exit(1)        }        //logs an incoming message        fmt.Printf(&amp;#x22;Received message %s -&gt; %s \n&amp;#x22;, conn.RemoteAddr(), conn.LocalAddr())        // Handle connections in a new goroutine.        go handleRequest(conn)    }}// Handles incoming requests.func handleRequest(conn net.Conn) {  // Make a buffer to hold incoming data.  buf := make([]byte, 1024)  // Read the incoming connection into the buffer.  reqLen, err := conn.Read(buf)  if err != nil {    fmt.Println(&amp;#x22;Error reading:&amp;#x22;, err.Error())  }  // Builds the message.  message := &amp;#x22;Hi, I received your message! It was &amp;#x22;  message += strconv.Itoa(reqLen)  message += &amp;#x22; bytes long and that&amp;#x27;s what it said: \&amp;#x22;&amp;#x22;  n := bytes.Index(buf, []byte{0})  message += string(buf[:n-1])  message += &amp;#x22;\&amp;#x22; ! Honestly I have no clue about what to do with your messages, so Bye Bye!\n&amp;#x22;  // Write the message in the connection channel.  conn.Write([]byte(message));  // Close the connection when you&amp;#x27;re done with it.  conn.Close()}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Ok, the code is commented at it should be understandable enough.
Let’s try if it works.&lt;/p&gt;
&lt;p&gt;Just launch the server with the command:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;go&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;server.go&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;go run server.go&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We will have our server running and it will print out something like:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Listening on :3333&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Listening on :3333&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Let’s open another terminal window to try to speak with him. We will use &lt;a href=&quot;http://wikipedia.org/wiki/Netcat&quot;&gt;netcat&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Hello server&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;nc&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;localhost&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3333&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;echo &amp;#x22;Hello server&amp;#x22; | nc localhost 3333&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That’s what we should see in the two terminal windows:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Go echo server terminal windows execution&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;699&quot; height=&quot;444&quot; src=&quot;https://loige.co/_astro/go-server-output.CWRriSGW_ZfO9Uf.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;The terminal window on the top is running our server and it logs all the received requests (by printing the incoming TCP address and the local one), while the second terminal is our client that sent out a simple “Hello server” message and received a &lt;em&gt;very useful&lt;/em&gt; response from the server.&lt;/p&gt;
&lt;p&gt;That’s all from the Go side. In the next part of the post we will see how to “dockerize” this simple Go app. For now, you can obviously quit the server with a &lt;code&gt;CTRL+C&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;dockerizing-the-application&quot;&gt;Dockerizing the application&lt;/h2&gt;
&lt;p&gt;Ok, now we want to &lt;em&gt;“dockerize”&lt;/em&gt; this simple application. Wait, what does &lt;em&gt;“dockerize”&lt;/em&gt; mean? Well, by &lt;em&gt;“dockerizing”&lt;/em&gt; an application we will be able to put the application itself and all its dependencies within a Docker container that can be easily shipped and executed elsewhere.&lt;/p&gt;
&lt;h3 id=&quot;images-containers-and-dockerfiles&quot;&gt;Images, Containers and Dockerfile(s)&lt;/h3&gt;
&lt;p&gt;An extract from the Docker documentation should make things a bit clearer:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Docker enables apps to be quickly assembled from components and eliminates the friction between development, QA, and production environments. As a result, IT can ship faster and run the same app, unchanged, on laptops, data center VMs, and any cloud.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are several ways to dockerize an application and create a dedicated Docker container. The one I prefer at the moment is by adopting a “&lt;em&gt;Dockerfile&lt;/em&gt;”.&lt;/p&gt;
&lt;p&gt;A “&lt;em&gt;Dockerfile&lt;/em&gt;” is a file called exactly &lt;code&gt;Dockerfile&lt;/code&gt; that contains several reproducible instructions to create a Docker &lt;em&gt;image&lt;/em&gt; from scratch.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;What the hell is an image and how it is different from a container?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you are a noob with Docker (like me) you are probably asking yourself this question. I want to quote a &lt;a href=&quot;http://stackoverflow.com/a/21499102/495177&quot;&gt;brilliant answer from stackoverflow&lt;/a&gt; that should make things a bit clearer:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An image is the set of layers that are built up and can be moved around. Images are read-only.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://docs.docker.io/en/latest/terms/image/&quot;&gt;http://docs.docker.io/en/latest/terms/image/&lt;/a&gt; &gt; &lt;a href=&quot;http://docs.docker.io/en/latest/terms/layer/&quot;&gt;http://docs.docker.io/en/latest/terms/layer/&lt;/a&gt;
A container is an active (or inactive if exited) stateful instantiation of an image.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://docs.docker.io/en/latest/terms/container/&quot;&gt;http://docs.docker.io/en/latest/terms/container/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Feel free to visit these links if things are not clear yet.&lt;/p&gt;
&lt;p&gt;Now let’s get back to our &lt;code&gt;Dockerfile&lt;/code&gt;. Every Dockerfile contains some metadata (base image from which to start, the name of the maintainer, etc.) and a set of instruction used to build the image. These instructions are usually used to “install” all the needed dependencies and describe how to execute the contained application.&lt;/p&gt;
&lt;h3 id=&quot;lets-write-the-dockerfile&quot;&gt;Let’s write the Dockerfile&lt;/h3&gt;
&lt;p&gt;Enough talking, let’s jump to the code:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;dockerfile&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; ubuntu:12.04&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;MAINTAINER&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Luciano Mammino&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; apt-get install -y python-software-properties&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; add-apt-repository ppa:duh/golang&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; apt-get update&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; apt-get install -y golang&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;ADD&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; server.go /var/server/server.go&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;EXPOSE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; 3333&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;CMD&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;go&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;run&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;/var/server/server.go&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;FROM ubuntu:12.04MAINTAINER Luciano MamminoRUN apt-get install -y python-software-propertiesRUN add-apt-repository ppa:duh/golangRUN apt-get updateRUN apt-get install -y golangADD server.go /var/server/server.goEXPOSE 3333CMD [&amp;#x22;go&amp;#x22;, &amp;#x22;run&amp;#x22;, &amp;#x22;/var/server/server.go&amp;#x22;]&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A reader mentioned in a &lt;a href=&quot;#comment-1881765009&quot;&gt;comment&lt;/a&gt; that this dockerfile is no longer working (probably the PPA has beem removed or its temporary unavailable). If that’s your case you can use a minimal dockerfile optimized for GoLang provided by in the &lt;a href=&quot;https://blog.golang.org/docker#TOC_3.&quot;&gt;GoLang blog&lt;/a&gt; itself.&lt;/p&gt;
&lt;p&gt;Let’s analyze all the instructions one by one:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;FROM ubuntu:12.04&lt;/code&gt; defines the base image from which to start. In this case we will use the &lt;code&gt;ubuntu:12.04&lt;/code&gt; image, a very lightweight image based on ubuntu 12.04.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;MAINTAINER Luciano Mammino&lt;/code&gt; isn’t it self-explanatory enough? ;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;RUN apt-get install -y python-software-properties&lt;/code&gt; installs the &lt;code&gt;python-software-properties&lt;/code&gt; package to be able to execute &lt;code&gt;add-apt-repository&lt;/code&gt; next.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;RUN add-apt-repository ppa:duh/golang&lt;/code&gt;, &lt;code&gt;RUN apt-get update&lt;/code&gt;, &lt;code&gt;RUN apt-get install -y golang&lt;/code&gt; and &lt;code&gt;RUN apt-get install -y golang&lt;/code&gt;: adds a custom repository for Go and installs it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ADD server.go /var/server/server.go&lt;/code&gt;: copies the file &lt;code&gt;server.go&lt;/code&gt; into the image (storing it into the &lt;code&gt;/var/server/&lt;/code&gt; folder)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;EXPOSE 3333&lt;/code&gt;: exposes the port 3333 to allow containers launched from this image to listen on this port. We need exactly this port because it is the one used by our Go application.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;CMD [&quot;go&quot;, &quot;run&quot;, &quot;/var/server/server.go&quot;]&lt;/code&gt;: describes the command to execute our Go application when the container is launched (yes, it will execute &lt;code&gt;go run /var/server/server.go&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;lets-build&quot;&gt;Let’s build!&lt;/h3&gt;
&lt;p&gt;Before building the image from our Dockerfile, if you are using &lt;code&gt;boot2docker&lt;/code&gt;, you need to run it with:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;boot2docker&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;start&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;boot2docker start&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In case it prints out something like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;2014/06/29 16:09:32 Started.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;2014/06/29 16:09:32 To connect the Docker client to the Docker daemon, please set:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;2014/06/29 16:09:32     export DOCKER_HOST=tcp://192.168.59.103:2375&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;2014/06/29 16:09:32 Started.2014/06/29 16:09:32 To connect the Docker client to the Docker daemon, please set:2014/06/29 16:09:32     export DOCKER_HOST=tcp://192.168.59.103:2375&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Run the suggested &lt;code&gt;export&lt;/code&gt; command. Also take note of the given IP address as we would need to use later to connect to our server.&lt;/p&gt;
&lt;p&gt;Now just &lt;code&gt;cd&lt;/code&gt; into the folder that contains the &lt;code&gt;Dockerfile&lt;/code&gt; and the &lt;code&gt;server.go&lt;/code&gt; file and run:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-t&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;goecho&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;docker build -t goecho .&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Notice the &lt;code&gt;.&lt;/code&gt; that refers to the current folder (yes you got it, it says Docker to look for a &lt;code&gt;Dockerfile&lt;/code&gt; whitin it).&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;-t goecho&lt;/code&gt; option is not mandatory and is used to “give a convenience name” to the resulting image.&lt;/p&gt;
&lt;p&gt;You will see a series of commands being executed (yes the ones we wrote within our Dockerfile) and, if everything goes well, you should see something like this at the end:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Successfully built 713c09526bc1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Successfully built 713c09526bc1&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;You can also execute&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;images&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;docker images&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;To list all the available images (you should see our &lt;code&gt;goecho&lt;/code&gt; on the top of the list).&lt;/p&gt;
&lt;p&gt;Our image is ready to be run and trasformed into a live container. We’ll see how to do it in the next part of the post.&lt;/p&gt;
&lt;h3 id=&quot;running-the-container&quot;&gt;Running the container&lt;/h3&gt;
&lt;p&gt;Running the image and having a live container is just a matter of running:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-i&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-t&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-p&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;3333:3333&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;goecho&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;docker run -i -t -p 3333:3333 goecho&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The options &lt;code&gt;-i&lt;/code&gt; and &lt;code&gt;-t&lt;/code&gt; allows us to execute the container into the interactive mode that allows us to shut it down with &lt;code&gt;CTRL+C&lt;/code&gt; when needed.&lt;/p&gt;
&lt;p&gt;The option &lt;code&gt;-p 3333:3333&lt;/code&gt; maps the container port 3333 to the same port on our machine. It will effectively allows us to talk with the echo server using the port 3333.&lt;/p&gt;
&lt;p&gt;Now our container is live and running and our server application is active.&lt;/p&gt;
&lt;p&gt;Let’s open a new terminal window and try again:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Hello server&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;nc&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;ip&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3333&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;echo &amp;#x22;Hello server&amp;#x22; | nc &lt;ip&gt; 3333&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;&amp;#x3C;ip&gt;&lt;/code&gt; is &lt;code&gt;localhost&lt;/code&gt; if you are not using &lt;code&gt;boot2docker&lt;/code&gt;. If you are using it you need to provide the IP of the intermediade virtual machine provided by &lt;code&gt;boot2docker&lt;/code&gt;. It is the one we recorded before, but if you can’t find it you can simply run &lt;code&gt;boot2docker ip&lt;/code&gt; to discover it (it’s usually &lt;code&gt;192.168.59.103&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;That’s only the very beginning with Docker, there are a bunch of other interesting features and approaches. I will probably write some other post while I will keep learning and using Docker, so stay tuned and write all your suggestions in the comments.&lt;/p&gt;
&lt;p&gt;Thank you&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/simple-echo-server-written-in-go-dockerized.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/simple-echo-server-written-in-go-dockerized.png" width="1200" height="630"/></media:content><category>server</category><category>go</category><category>docker</category><author>Luciano Mammino</author><comments>https://loige.co/simple-echo-server-written-in-go-dockerized/#comments</comments><enclosure url="https://loige.co/og/simple-echo-server-written-in-go-dockerized.png" length="0" type="image/png"/></item><item><title>Backup your server with Dropbox</title><link>https://loige.co/backup-your-server-with-dropbox/</link><guid isPermaLink="true">https://loige.co/backup-your-server-with-dropbox/</guid><description>This post explains how to install Dropbox command line client on a Linux server, create a dedicated user and setup it as a service to have automated backups on Dropbox cloud.</description><pubDate>Fri, 17 Jan 2014 03:44:19 GMT</pubDate><content:encoded>&lt;p&gt;In my early days as &lt;em&gt;CTO&lt;/em&gt; at &lt;a href=&quot;http://sbaam.com&quot;&gt;Sbaam&lt;/a&gt; I had to setup a web server from the ground up. As it happens in many startups the work had to be done quickly and with an &lt;em&gt;almost-0-budget&lt;/em&gt;, so it left no space to sophisticated solutions for recurring tasks such as &lt;strong&gt;backup&lt;/strong&gt;. I always have been a web developer and focused on coding so, I admit I had really a poor knowledge about how to setup a remote unix virtual machine.&lt;/p&gt;
&lt;p&gt;So, speaking about backups, I needed a solution that would be cost-effective, easy to install and easy to maintain at the same time. I would have loved it if it can be as simple as sharing a &lt;a href=&quot;https://db.tt/ref37L7&quot;&gt;Dropbox&lt;/a&gt; folder. As this thought crossed my mind I wondered if there was some way to interact with dropbox from a script to create files and folders and started googling about it. Luckily Dropbox offers a good command line client that allows to bring your synced files and folders also on graphic-less machines.&lt;/p&gt;
&lt;p&gt;Ultimately my solution was to install the Dropbox command line on the server using a dedicated Dropbox account and backup files by simply copying/linking them on the Dropbox folder. This way I prepared and scheduled a script that simply had to copy the files I wanted to backup on the dropbox folder. Then I have the files backupped in the cloud and automatically synced on my local machine. Furthermore i had chance to share the backup folder with all my collaborators.&lt;/p&gt;
&lt;p&gt;This solution works very well for small projects so I will resume all the steps I followed to install and use dropbox this way. I used an &lt;em&gt;ubuntu&lt;/em&gt; machine so I suppose the following steps should work on debian machines.&lt;/p&gt;
&lt;h2 id=&quot;prepare-the-dropbox-user&quot;&gt;Prepare the dropbox user&lt;/h2&gt;
&lt;p&gt;I preferred to have a dedicated user to handle the whole Dropbox daemon and folder so just create it now:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;useradd&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-d&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/dropbox&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-m&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;dropbox&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sudo useradd -d /dropbox -m dropbox&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;It will have the directory &lt;code&gt;/dropbox&lt;/code&gt; as home and the name &lt;code&gt;dropbox&lt;/code&gt;. You can change these values if you like.&lt;/p&gt;
&lt;p&gt;Then you have to set the password for the new user:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;passwd&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;dropbox&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sudo passwd dropbox&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Choose whatever password you like.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Security concern:&lt;/strong&gt; If you have ssh access enabled (obviously it is) it’s better to disable the ssh access for the new user. So edit the file &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; and add the rule &lt;code&gt;DenyUsers dropbox&lt;/code&gt;, the restart ssh with &lt;code&gt;sudo service ssh restart&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;install-the-dropbox-client&quot;&gt;Install the dropbox client&lt;/h2&gt;
&lt;p&gt;First of all you need to switch to the user created in the previous step, so the Dropbox installer will create the Dropbox folder under its home. At the end you will have &lt;code&gt;/dropbox/Dropbox&lt;/code&gt; as the synced folder:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;su&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;dropbox&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;su dropbox&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;(enter the password for the user dropbox)&lt;/p&gt;
&lt;p&gt;Now you’re the &lt;em&gt;dropbox&lt;/em&gt; user. Be sure to switch to your user folder with &lt;code&gt;cd ~&lt;/code&gt; and let’s download and install the daemon.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;wget&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-O&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;dropbox.tar.gz&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;http://www.dropbox.com/download/?plat=lnx.x86&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;wget -O dropbox.tar.gz &amp;#x22;http://www.dropbox.com/download/?plat=lnx.x86&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;for 32bit or&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;wget&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-O&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;dropbox.tar.gz&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;http://www.dropbox.com/download/?plat=lnx.x86_64&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;wget -O dropbox.tar.gz &amp;#x22;http://www.dropbox.com/download/?plat=lnx.x86_64&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;for 64bit.&lt;/p&gt;
&lt;p&gt;Extract it:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;tar&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-xvzf&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;dropbox.tar.gz&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;tar -xvzf dropbox.tar.gz&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;It will extract to the &lt;code&gt;~/.dropbox-dist.&lt;/code&gt; folder. Now run the client:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;~/.dropbox-dist/dropbox&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;~/.dropbox-dist/dropbox&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;You will see an output like the following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This client is not linked to any account…
Please visit {SOME_URL} to link this machine. […]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Copy and paste the provided URL in the browser bar of your local machine and it will ask you to enter the password of your dropbox account. This way it is able to authenticate your command line client and start syncing your files. At this point it should have been started its work but our shell is still locked by the client. We need to kill and daemonize it to being able to manage it as a service. Press &lt;code&gt;CTRL+C&lt;/code&gt; and get back to your user with the &lt;code&gt;exit&lt;/code&gt; command.&lt;/p&gt;
&lt;h2 id=&quot;dropbox-as-a-service&quot;&gt;Dropbox as a service&lt;/h2&gt;
&lt;p&gt;At this point we need to define dropbox as a service. So let’s create an &lt;em&gt;etc init script&lt;/em&gt;. Download &lt;a href=&quot;https://gist.github.com/lmammino/8467336&quot;&gt;my gist&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;wget&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-O&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;dropbox_init_script&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;https://gist.github.com/lmammino/8467336/raw/dropbox&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;wget -O dropbox_init_script &amp;#x22;https://gist.github.com/lmammino/8467336/raw/dropbox&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;and move it in the init folder:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;mv&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;dropbox_init_script&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/etc/init.d/dropbox&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sudo mv dropbox_init_script /etc/init.d/dropbox&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Make it executable:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;+x&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/etc/init.d/dropbox&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sudo chmod +x /etc/init.d/dropbox&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And set it to load at startup:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;update-rc.d&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;dropbox&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;defaults&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sudo update-rc.d dropbox defaults&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now it’s a service! Run:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/etc/init.d/dropbox&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;start&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sudo /etc/init.d/dropbox start&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;to start it and feel free to use common service command such as &lt;code&gt;stop&lt;/code&gt;, &lt;code&gt;restart&lt;/code&gt; and &lt;code&gt;status&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;enjoy&quot;&gt;Enjoy&lt;/h2&gt;
&lt;p&gt;At this point you have all your dropbox data in the &lt;code&gt;/dropbox/Dropbox&lt;/code&gt; folder. Feel free to copy all the files you want in there or to schedule jobs that does all the dirty work for you. You can also create symlinks into the dropbox folder to keep files and folders placed in other locations synced.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Security concerns&lt;/strong&gt;: consider that your dropbox folder acts as a normal dropbox folder so it’s synced both ways. If someone breaks into your dropbox account (or the account of some collaborator who shares the folder with you) he can use dropbox as an hole to inject malicious files into your server or steal sensible data. So, for example, avoid to have scheduled scripts and unencrypted sensible data in that folder.&lt;/p&gt;
&lt;h2 id=&quot;bonus&quot;&gt;Bonus&lt;/h2&gt;
&lt;p&gt;Dropbox released the &lt;a href=&quot;https://www.dropbox.com/download?dl=packages/dropbox.py&quot;&gt;Dropbox CLI&lt;/a&gt;, a python command line application that you can use to perform some useful task such as &lt;em&gt;Selective Sync&lt;/em&gt;, disable the &lt;em&gt;LAN sync&lt;/em&gt; or retrive public links of your files. I suggest to download it by using the dropbox user and place it under &lt;code&gt;/dropbox/bin&lt;/code&gt;. So you can simply switch to the dropbox user (again with &lt;code&gt;su dropbox&lt;/code&gt;), download it and make it executable:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;~/bin&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;wget&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-O&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;~/bin/dropbox.py&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;https://www.dropbox.com/download?dl=packages/dropbox.py&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;+x&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;~/bin/dropbox.py&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;mkdir ~/binwget -O ~/bin/dropbox.py &amp;#x22;https://www.dropbox.com/download?dl=packages/dropbox.py&amp;#x22;chmod +x ~/bin/dropbox.py&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;At this point you can run the Dropbox CLI. For example if you want to disable the LAN sync (heavily suggested in this case) you can simply do:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;/dropbox/bin/dropbox.py&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;lansync&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;n&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;/dropbox/bin/dropbox.py lansync n&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;p&gt;That’s all.
It was a long read but I hope it has been useful ;)&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/backup-your-server-with-dropbox.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/backup-your-server-with-dropbox.png" width="1200" height="630"/></media:content><category>backup</category><category>dropbox</category><category>server</category><author>Luciano Mammino</author><comments>https://loige.co/backup-your-server-with-dropbox/#comments</comments><enclosure url="https://loige.co/og/backup-your-server-with-dropbox.png" length="0" type="image/png"/></item><item><title>Developing a web application with Lumen and MySql</title><link>https://loige.co/developing-a-web-application-with-lumen-and-mysql/</link><guid isPermaLink="true">https://loige.co/developing-a-web-application-with-lumen-and-mysql/</guid><description>This tutorial shows step-by-step how to bootstrap a Lumen project, configure MySQL, create migrations and models, seed the database, define routes and templates to build a fully working motivational quote web app in less than 30 minutes.</description><pubDate>Sat, 18 Apr 2015 16:10:35 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://lumen.laravel.com/&quot;&gt;Lumen&lt;/a&gt; is a new &lt;a href=&quot;/tag/php&quot;&gt;Php&lt;/a&gt; micro-framework developed by &lt;a href=&quot;https://twitter.com/taylorotwell&quot;&gt;Taylor Otwell&lt;/a&gt;, the same author of the famous &lt;a href=&quot;http://laravel.com/&quot;&gt;Laravel&lt;/a&gt; framework. I wanted to give it a try and I am here to share my experimentations. I am not an expert of Lumen (yet), but I think one of the best characteristics of this framework is that it makes really really easy to bootstrap a new project.
So to prove this, we will now build a fully functional app backed by a MySql database in less than 30 minutes. Are you ready to start?&lt;/p&gt;
&lt;h2 id=&quot;a-motivational-quote-everyday&quot;&gt;A motivational quote everyday&lt;/h2&gt;
&lt;p&gt;Our app should be quite simple but I’d like also to make something useful. I am a big fan of motivational quotes, and if you &lt;a href=&quot;https://twitter.com/loige&quot;&gt;follow me on Twitter&lt;/a&gt; (&lt;strong&gt;you should!&lt;/strong&gt;) you probably &lt;a href=&quot;https://twitter.com/loige/status/588075619377885186&quot;&gt;already know it&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;So, the idea is to build a web app that showcases a new quote everyday. This way, everyday when you wake up you can run your application and be inspired and motivated by a wise and energising quote to do your best!
To work best our app should obviously be fancy, with über cool background images, like in the screenshot above. That’s an importante detail!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Motivational quotes Lumen Php app screenshot&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;800&quot; height=&quot;591&quot; src=&quot;https://loige.co/_astro/motivation-quote-app-screenshoot.CgMTt89j_ZUiK8Y.webp&quot; &gt;&lt;/p&gt;
&lt;h2 id=&quot;a-new-lumen-project&quot;&gt;A new Lumen project&lt;/h2&gt;
&lt;p&gt;Let’s start. First of all, to create a new Lumen project, we need to have the Lumen command line installer. A very simple tool, which in turn uses Composer, that allow us to bootstrap a new Lumen project in few seconds. To get it ensure to have installed Composer globally and run the following command:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;composer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;global&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;laravel/lumen-installer=~1.0&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;composer global require &amp;#x22;laravel/lumen-installer=~1.0&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: you might need to use &lt;code&gt;sudo&lt;/code&gt;, depending on the way you installed Composer.&lt;/p&gt;
&lt;p&gt;Once we have done this we have a new toy in our shell: the &lt;code&gt;lumen&lt;/code&gt; command. We can now create a new project by running:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;lumen&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;motivational&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;lumen new motivational&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;motivational&lt;/strong&gt; is the name of our new app. The command creates a new folder for it and downloads all the dependencies.&lt;/p&gt;
&lt;p&gt;To see our application live we need to &lt;code&gt;cd&lt;/code&gt; into our &lt;code&gt;motivational&lt;/code&gt; folder and run&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;php&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;artisan&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;serve&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;php artisan serve&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Our project will be immediately up and running on &lt;code&gt;http://localhost:8000&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;define-the-data-model&quot;&gt;Define the data model&lt;/h2&gt;
&lt;p&gt;We said we want to showcase quotes and in our case a quote is made up by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;text&lt;/strong&gt; (The quoted text itself)&lt;/li&gt;
&lt;li&gt;an &lt;strong&gt;author&lt;/strong&gt; (The name of the author of the quote)&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;background&lt;/strong&gt; image (Yes, to make everything fancier)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In order to manage data from the database, we need to enable &lt;a href=&quot;http://laravel.com/docs/5.0/eloquent&quot;&gt;Eloquent&lt;/a&gt; (the Lumen/Laravel ORM library), configure our database connection, create a migration and a model and finally seed our database. Let’s do it step by step.&lt;/p&gt;
&lt;h2 id=&quot;enable-eloquent&quot;&gt;Enable Eloquent&lt;/h2&gt;
&lt;p&gt;To enable Eloquent we need to edit the file &lt;code&gt;bootstrap/app.php&lt;/code&gt; and remove the comment on the following lines:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$app&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;withFacades&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$app&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;withEloquent&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$app-&gt;withFacades();$app-&gt;withEloquent();&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Notice that the first line enables the support for &lt;a href=&quot;http://laravel.com/docs/5.0/facades&quot;&gt;Facades&lt;/a&gt; (a very common feature used in Laravel and inherited by Lumen) that simplifies the usage of some of the core classes of the framework.&lt;/p&gt;
&lt;h2 id=&quot;configure-the-database-connection&quot;&gt;Configure the database connection&lt;/h2&gt;
&lt;p&gt;First of all, be sure to have an instance of MySql running on your machine and to have the credentials to connect to it. Now let’s create our &lt;code&gt;.env&lt;/code&gt; (Dotenv) configuration file. Copy the &lt;code&gt;.env.example&lt;/code&gt; file into a new &lt;code&gt;.env&lt;/code&gt; file and open it in your favourite editor.&lt;/p&gt;
&lt;p&gt;Here we need to edit the following lines and provide the details needed to connect to our local mysql instance:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ini&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;DB_CONNECTION&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=mysql&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;DB_HOST&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=localhost&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;DB_DATABASE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=homestead&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;DB_USERNAME&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=homestead&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;DB_PASSWORD&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=secret&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;DB_CONNECTION=mysqlDB_HOST=localhostDB_DATABASE=homesteadDB_USERNAME=homesteadDB_PASSWORD=secret&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Be sure to create the database (&lt;code&gt;homestead&lt;/code&gt; in this case, but you can obviously customise it).&lt;/p&gt;
&lt;p&gt;It’s also a good idea in general to change the &lt;code&gt;APP_KEY&lt;/code&gt; value into some random string in case you are building a “serious” application.&lt;/p&gt;
&lt;p&gt;To make Lumen load this configuration file we need, again, to edit the &lt;code&gt;bootstrap/app.php&lt;/code&gt; file and uncomment the following line:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Dotenv&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;load&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;__DIR__&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D67B7B;--1:#016C9A&quot;&gt;&apos;/../&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Dotenv::load(__DIR__.&amp;#x27;/../&amp;#x27;);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;create-a-migration&quot;&gt;Create a migration&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://laravel.com/docs/5.0/migrations&quot;&gt;Migrations&lt;/a&gt; allows the framework to keep the database schema under control. They define all the database tables and fields programmatically and keep track of the various changes on them (so that we can easily update and rollback the whole schema when needed). We need to initialise the migration system with the command:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;php&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;artisan&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;migrate:install&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;php artisan migrate:install&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This command creates a special table in our database called &lt;code&gt;migrations&lt;/code&gt; that will be used internally from the framework to keep track of all the available migrations and the current one used.&lt;/p&gt;
&lt;p&gt;Every migrations is identified by a file that generally lives in the &lt;code&gt;database/migrations&lt;/code&gt; folder. The file describes the changes in our schema (eg. new tables, new fields, new indexes, tables to be deleted, etc…). In our case we need to create a new table, the “quotes” table to be precise. Let’s run this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;php&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;artisan&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;make:migration&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--create=quotes&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;create_quotes_table&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;php artisan make:migration --create=quotes create_quotes_table&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;It creates a new file under the &lt;code&gt;database/migrations&lt;/code&gt; folder that we can easily edit to add the fields we want to have in our table. We just need to tweak the &lt;code&gt;up()&lt;/code&gt; function a bit:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;up&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Schema&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;quotes&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Blueprint&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$table&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;         &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$table&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;increments&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;               &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$table&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;timestamps&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;         &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// our new fields&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;               &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$table&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;               &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$table&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;author&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;               &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$table&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;background&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;public function up(){    Schema::create(&amp;#x27;quotes&amp;#x27;, function(Blueprint $table)    {         $table-&gt;increments(&amp;#x27;id&amp;#x27;);               $table-&gt;timestamps();         // our new fields               $table-&gt;string(&amp;#x27;text&amp;#x27;);               $table-&gt;string(&amp;#x27;author&amp;#x27;);               $table-&gt;string(&amp;#x27;background&amp;#x27;);    });}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;To execute the migration (and effectively create the table on the database) we have to run:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;php&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;artisan&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;migrate&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;php artisan migrate&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;create-the-quote-model&quot;&gt;Create the Quote model&lt;/h2&gt;
&lt;p&gt;In general, a model is a class used to abstract our data and represent it as an object. In ORMs a model class also offers static methods to query the data storage to retrieve the data from the data source and create the corresponding objects.&lt;/p&gt;
&lt;p&gt;In our case we need to define the &lt;code&gt;Quote&lt;/code&gt; model in &lt;code&gt;app/Models/Quote.php&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;app/Models/Quote.php&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;php&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;App\Models&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Illuminate\Database\Eloquent\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Model&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Quote&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Model&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;?phpnamespace App\Models;use Illuminate\Database\Eloquent\Model;final class Quote extends Model{}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Yes, that’s it… we don’t really need to write anything else! We are extending the Eloquent &lt;code&gt;Model&lt;/code&gt; class that does all the hard work for us, proving a standard model configuration that is good enough most of the times. In this case it automatically maps the class &lt;code&gt;Quote&lt;/code&gt; to the &lt;code&gt;quotes&lt;/code&gt; table that we created before.&lt;/p&gt;
&lt;h2 id=&quot;seed-the-database&quot;&gt;Seed the database&lt;/h2&gt;
&lt;p&gt;The seeding process allows us to populate our database with initial data. In our case we can use it to provide some quotes. It’s quite useful because we will not build a full fledged admin to do the data entry at this stage (and we also will not have to touch the database manually).&lt;/p&gt;
&lt;p&gt;Seeds files are stored in &lt;code&gt;database/seeds&lt;/code&gt; and we need to create a new file there. We will call it &lt;code&gt;QuoteTableSeeder.php&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;database/seeds/QuoteTableSeeder.php&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;php&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; App\Models\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Quote&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; Illuminate\Database\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Seeder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;QuoteTableSeeder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Seeder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Quote&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;([&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Success is going from failure to failure without losing your enthusiasm&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;author&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Winston Churchill&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;background&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;1.jpg&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Quote&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;([&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Dream big and dare to fail&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;author&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Norman Vaughan&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;background&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;2.jpg&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Quote&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;([&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;It does not matter how slowly you go as long as you do not stop&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;author&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Confucius&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;background&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;3.jpg&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//... add more quotes if you want!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;?phpuse App\Models\Quote;use Illuminate\Database\Seeder;class QuoteTableSeeder extends Seeder{    public function run()    {        Quote::create([            &amp;#x27;text&amp;#x27; =&gt; &amp;#x27;Success is going from failure to failure without losing your enthusiasm&amp;#x27;,            &amp;#x27;author&amp;#x27; =&gt; &amp;#x27;Winston Churchill&amp;#x27;,            &amp;#x27;background&amp;#x27; =&gt; &amp;#x27;1.jpg&amp;#x27;        ]);        Quote::create([            &amp;#x27;text&amp;#x27; =&gt; &amp;#x27;Dream big and dare to fail&amp;#x27;,            &amp;#x27;author&amp;#x27; =&gt; &amp;#x27;Norman Vaughan&amp;#x27;,            &amp;#x27;background&amp;#x27; =&gt; &amp;#x27;2.jpg&amp;#x27;        ]);        Quote::create([            &amp;#x27;text&amp;#x27; =&gt; &amp;#x27;It does not matter how slowly you go as long as you do not stop&amp;#x27;,            &amp;#x27;author&amp;#x27; =&gt; &amp;#x27;Confucius&amp;#x27;,            &amp;#x27;background&amp;#x27; =&gt; &amp;#x27;3.jpg&amp;#x27;        ]);        //... add more quotes if you want!    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The code is quite self explanatory: every call to &lt;code&gt;Quote::create&lt;/code&gt; inserts a new record into the &lt;code&gt;quotes&lt;/code&gt; table with the data provided into the array passed as argument. The only thing worth noticing is that we are passing a relative reference to a file in the &lt;code&gt;background&lt;/code&gt; field. You need to have these files into your &lt;code&gt;public/img/&lt;/code&gt; folder, as this allows us to serve these files to the browser. If you need some good royalty-free photos have a look at the &lt;a href=&quot;http://unsplash.com&quot;&gt;Unsplash project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To enable this seed script we need to link it to the main &lt;code&gt;DatabaseSeeder&lt;/code&gt; script by adding the following line within the &lt;code&gt;run()&lt;/code&gt; method:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;QuoteTableSeeder&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;$this-&gt;call(&amp;#x27;QuoteTableSeeder&amp;#x27;);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now we just need to launch the following command to execute the seed script and populate the database:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;php&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;artisan&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;db:seed&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;php artisan db:seed&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Damn, we got a &lt;code&gt;Class QuoteTableSeeder does not exist&lt;/code&gt;! That’s why by default Lumen Composer file maps the &lt;code&gt;database&lt;/code&gt; path with the &lt;code&gt;classmap&lt;/code&gt; strategy. That means that every time Composer dumps the autoloader, it creates a static map of all the classes available inside that folder. So every time we add a new class there we need to manually re-dump the autoloader script:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;composer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;dump-autoload&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;composer dump-autoload&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now let’s run again &lt;code&gt;php artisan db:seed&lt;/code&gt; and this time everything should be fine.
If you explore your database you will see some records within the &lt;code&gt;quotes&lt;/code&gt; table.&lt;/p&gt;
&lt;h2 id=&quot;the-routing&quot;&gt;The routing&lt;/h2&gt;
&lt;p&gt;Until now we just defined the data model of our application and populated our database. Now we will add some business logic and we will map it to some routes.&lt;/p&gt;
&lt;p&gt;We will have two routes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GET &lt;code&gt;/&lt;/code&gt; - the main route, providing a new quote everyday&lt;/li&gt;
&lt;li&gt;GET &lt;code&gt;/{id}&lt;/code&gt; - the route of a specific quote, mapped by id&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To define the business logic associate to a route we have to edit the &lt;code&gt;app/Http/routes.php&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;app/Http/routes.php&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;php&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; App\Models\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Quote&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* Display the today quote&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$app&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$app&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* Picks a different quote every day&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* (for a maximum of 366 quotes)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*   - $count: the total number of available quotes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*   - $day: the current day of the year (from 0 to 365)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*   - $page: the page to look for to retrieve the&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*            correct record&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;     &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$count&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Quote&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$day&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = (&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;z&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$page&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$day&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; % &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$count&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; + &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$quotes&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Quote&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;forPage&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$page&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;all&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;empty&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$quotes&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; \Illuminate\Database\Eloquent\&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;ModelNotFoundException&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;view&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;quote&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, [&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;quote&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$quotes&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* Display a specific quote&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$app&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/{id}&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$app&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$quote&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Quote&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()-&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;findOrFail&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;view&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;quote&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, [&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;quote&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$quote&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;?phpuse App\Models\Quote;/** * Display the today quote */$app-&gt;get(&amp;#x27;/&amp;#x27;, function() use ($app) {    /*     * Picks a different quote every day     * (for a maximum of 366 quotes)     *     *   - $count: the total number of available quotes     *   - $day: the current day of the year (from 0 to 365)     *   - $page: the page to look for to retrieve the     *            correct record     */    $count = Quote::query()-&gt;get()-&gt;count();    $day = (int) date(&amp;#x27;z&amp;#x27;);    $page = $day % $count + 1;    $quotes = Quote::query()-&gt;get()-&gt;forPage($page, 1)-&gt;all();    if (empty($quotes)) {        throw new \Illuminate\Database\Eloquent\ModelNotFoundException();    }    return view(&amp;#x27;quote&amp;#x27;, [&amp;#x27;quote&amp;#x27; =&gt; $quotes[0]]);});/** * Display a specific quote */$app-&gt;get(&amp;#x27;/{id}&amp;#x27;, function($id) use ($app) {    $quote = Quote::query()-&gt;findOrFail($id);    return view(&amp;#x27;quote&amp;#x27;, [&amp;#x27;quote&amp;#x27; =&gt; $quote]);});&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The two &lt;code&gt;$app-&gt;get&lt;/code&gt; defines the two routes we need for our app. For every route we define the business logic within a closure function. The code is very straightforward and, thanks to the comments, it should be quite easy to understand.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;view()&lt;/code&gt; function allow to render a template. In this case we are rendering the &lt;code&gt;quote&lt;/code&gt; template passing the model as &lt;code&gt;quote&lt;/code&gt; variable. In the next paragraph we will see how to define our template.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: if you don’t want to use closures in your routing and you want to have a greater control on the structure of your code and your business logic you can leverage Laravel’s controllers. I will not go into the detail of this, but you can check the &lt;a href=&quot;http://lumen.laravel.com/docs/controllers&quot;&gt;Documentation&lt;/a&gt; that shows how to do it. It’s quite simple anyway.&lt;/p&gt;
&lt;h2 id=&quot;the-template&quot;&gt;The template&lt;/h2&gt;
&lt;p&gt;Lumen uses the Laravel default template language, &lt;a href=&quot;http://lumen.laravel.com/docs/templates&quot;&gt;Blade&lt;/a&gt;. Blade allows us to render complex HTML code in a easy way. All the templates live in the &lt;code&gt;resources/views&lt;/code&gt; folder. Let’s create the &lt;code&gt;quote.blade.php&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;resources/views/quote.blade.php&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;Motivaitonal — Your daily source of motivation!&lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;/css/style.css&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;rel&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;text/css&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;/&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;http://fonts.googleapis.com/css?family=Alegreya:400,700|Roboto+Condensed&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;rel&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;stylesheet&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;text/css&apos;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#383A42&quot;&gt;background-image: url(&apos;/img/{{$quote-&gt;background}}&apos;)&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;quote-container&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;{{$quote-&gt;text}}&lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;— {{$quote-&gt;author}}&lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;html&gt;&lt;head&gt;    &lt;title&gt;Motivaitonal — Your daily source of motivation!&lt;/title&gt;    &lt;link href=&amp;#x22;/css/style.css&amp;#x22; rel=&amp;#x22;stylesheet&amp;#x22; type=&amp;#x22;text/css&amp;#x22;/&gt;    &lt;link href=&amp;#x27;http://fonts.googleapis.com/css?family=Alegreya:400,700|Roboto+Condensed&amp;#x27; rel=&amp;#x27;stylesheet&amp;#x27; type=&amp;#x27;text/css&amp;#x27;&gt;&lt;/head&gt;&lt;body style=&amp;#x22;background-image: url(&amp;#x27;/img/{{$quote-&gt;background}}&amp;#x27;)&amp;#x22;&gt;&lt;div class=&amp;#x22;container&amp;#x22;&gt;    &lt;div class=&amp;#x22;quote-container&amp;#x22;&gt;        &lt;p class=&amp;#x22;text&amp;#x22;&gt;{{$quote-&gt;text}}&lt;/p&gt;        &lt;p class=&amp;#x22;author&amp;#x22;&gt;— {{$quote-&gt;author}}&lt;/p&gt;    &lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;As you can see we can use the double curly braces syntax to reference variable values.&lt;/p&gt;
&lt;p&gt;To finish we just need to create our &lt;code&gt;public/css/style.css&lt;/code&gt; stylesheet file:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#AF4238&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#A626A4&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#AF4238&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;height&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;100%&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;padding&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;margin&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#AF4238&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;background-size&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#383A42&quot;&gt;cover&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#875D01&quot;&gt;.container&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;height&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;100%&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;background&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;rgba&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0.3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#875D01&quot;&gt;.quote-container&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;position&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#383A42&quot;&gt;relative&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;top&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;50%&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;transform&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;translateY&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;-50%&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;padding&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2em&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;4em&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#875D01&quot;&gt;.quote-container&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#A626A4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#AF4238&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;text-align&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#383A42&quot;&gt;center&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;color&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#875D01&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#016C9A&quot;&gt;fff&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;text-shadow&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1px&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1px&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1px&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;rgba&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;150&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;150&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;150&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0.8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#875D01&quot;&gt;.quote-container&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#A626A4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#AF4238&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#875D01&quot;&gt;.text&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;font-family&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Alegreya&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#875D01&quot;&gt;serif&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;font-size&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;4em&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#875D01&quot;&gt;.quote-container&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#A626A4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#AF4238&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#875D01&quot;&gt;.author&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;font-family&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Roboto Condensed&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#875D01&quot;&gt;sans-serif&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;font-size&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1.2em&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;html,body {  height: 100%;  padding: 0;  margin: 0;}body {  background-size: cover;}.container {  height: 100%;  background: rgba(0, 0, 0, 0.3);}.quote-container {  position: relative;  top: 50%;  transform: translateY(-50%);  padding: 2em 4em;}.quote-container p {  text-align: center;  color: #fff;  text-shadow: 1px 1px 1px rgba(150, 150, 150, 0.8);}.quote-container p.text {  font-family: &amp;#x27;Alegreya&amp;#x27;, serif;  font-size: 4em;}.quote-container p.author {  font-family: &amp;#x27;Roboto Condensed&amp;#x27;, sans-serif;  font-size: 1.2em;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That’s it, now your app is up and running. Isn’t it beautiful? Hey, let me know if you decide to publish it and motivate the whole world! ;)&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;Lumen seems to be a very promising framework for the fast prototyping of small web apps. I look forward to use it again for slightly more complex use cases where I can adopt other interesting features like the &lt;a href=&quot;http://lumen.laravel.com/docs/cache&quot;&gt;cache layer&lt;/a&gt; and the &lt;a href=&quot;http://lumen.laravel.com/docs/queues&quot;&gt;job queue library&lt;/a&gt;.
Have you already used Lumen? Do you think it will become a mainstream framework along Laravel or it will just be another of the hundreds of &lt;a href=&quot;/tag/php&quot;&gt;Php&lt;/a&gt; framework available out there? I’m really curious to know what you think about it, let me know it in the comments!&lt;/p&gt;
&lt;p&gt;Best regards and have a very motivated day ;)&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/developing-a-web-application-with-lumen-and-mysql.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/developing-a-web-application-with-lumen-and-mysql.png" width="1200" height="630"/></media:content><category>php</category><category>mysql</category><category>lumen</category><category>laravel</category><author>Luciano Mammino</author><comments>https://loige.co/developing-a-web-application-with-lumen-and-mysql/#comments</comments><enclosure url="https://loige.co/og/developing-a-web-application-with-lumen-and-mysql.png" length="0" type="image/png"/></item><item><title>Versioning and deploying a static website with Git, Flightplan and Nginx</title><link>https://loige.co/versioning-and-deploying-a-static-website-with-git-flightplan-and-nginx/</link><guid isPermaLink="true">https://loige.co/versioning-and-deploying-a-static-website-with-git-flightplan-and-nginx/</guid><description>This blog post provides a beginner&apos;s guide to managing versioning and deployment of static websites using Git for version control, Flightplan.js for automated deployment, and Nginx for serving. It outlines a simple yet complete workflow for implementing continuous delivery and rollbacks.</description><pubDate>Tue, 08 Sep 2015 22:16:27 GMT</pubDate><content:encoded>&lt;p&gt;Do you ever wondered how to manage the &lt;strong&gt;versioning&lt;/strong&gt; and &lt;strong&gt;deployment&lt;/strong&gt; process of a website? It seems to be a very interesting yet complex topic for which there are already thousands of different solutions.
In a recent collaboration with &lt;a href=&quot;http://usersnap.com/&quot;&gt;Usersnap&lt;/a&gt; I had the pleasure to write a very detailed article for their blog that proposes a solution based on &lt;strong&gt;&lt;a href=&quot;https://github.com/pstadler/flightplan&quot;&gt;Flightplan.js&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;Git&lt;/strong&gt; and &lt;strong&gt;Nginx&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;My solution is very simple, it requires very few dependencies on your system (Git and Node.js) and it has been thought to give you the basics of how to define a minimal yet complete setup that it’s easy to customize and extend for more complex requirements.&lt;/p&gt;
&lt;p&gt;Without further ado I really advice you to go and read the article on the Usersnap blog:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://usersnap.com/blog/deploying-static-websites-flightplan/&quot;&gt;A beginner’s guide to deploying static sites with versioning and rollbacks using Flightplan&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://usersnap.com/blog/deploying-static-websites-flightplan/&quot;&gt;&lt;img alt=&quot;A beginner&amp;amp;#x27;s guide to deploying static websites&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;692&quot; height=&quot;400&quot; src=&quot;https://loige.co/_astro/a-beginner-s-guide-to-deploying-static-websites-1.B1O1zlbx_Z1lgJv1.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you like the article or you have any question or comment, please use the comment box on the Usersnap blog post.&lt;/p&gt;
&lt;p&gt;Cheers :)&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/versioning-and-deploying-a-static-website-with-git-flightplan-and-nginx.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/versioning-and-deploying-a-static-website-with-git-flightplan-and-nginx.png" width="1200" height="630"/></media:content><category>javascript</category><category>server</category><category>node-js</category><category>nginx</category><category>git</category><category>flightplan</category><category>collaboration</category><author>Luciano Mammino</author><comments>https://loige.co/versioning-and-deploying-a-static-website-with-git-flightplan-and-nginx/#comments</comments><enclosure url="https://loige.co/og/versioning-and-deploying-a-static-website-with-git-flightplan-and-nginx.png" length="0" type="image/png"/></item><item><title>Introducing mongo-uri-builder, a Node.js module to easily create mongodb connection strings using objects</title><link>https://loige.co/introducing-mongo-uri-builder-a-nodejs-module-to-easily-create-mongodb-connection-strings-using-objects/</link><guid isPermaLink="true">https://loige.co/introducing-mongo-uri-builder-a-nodejs-module-to-easily-create-mongodb-connection-strings-using-objects/</guid><description>The mongo-uri-builder Node.js package easily generates MongoDB connection strings from configuration objects, supporting features like authentication, replicas, and options. It integrates well with config for managing different environments.</description><pubDate>Tue, 29 Sep 2015 23:07:02 GMT</pubDate><content:encoded>&lt;p&gt;A couple of days ago I had the need to store the MongoDB connection string for a Node.js application I am currently building.
Of course it was not a big deal and at first I stored it in a file.
Anyway at some point I realised that I would needed to override parts of this string to change some settings in &lt;em&gt;production&lt;/em&gt; (e.g. adding replicas and authentication settings).
For this sake it would have been nice to have a way to store this configuration as a “well organised” object and then override just the properties I wanted to change.&lt;/p&gt;
&lt;p&gt;I often use the &lt;a href=&quot;https://www.npmjs.com/package/config&quot;&gt;config&lt;/a&gt; module to store my configuration and so I wanted to be able to do something like this in my configuration file:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;mongo&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;host&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;localhost&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;port&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;27017&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;database&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;mydb&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;username&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;loige&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;password&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;whyDoYouWantToKnowMyPassword&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{  &amp;#x22;mongo&amp;#x22;: {    &amp;#x22;host&amp;#x22;: &amp;#x22;localhost&amp;#x22;,    &amp;#x22;port&amp;#x22;: 27017,    &amp;#x22;database&amp;#x22;: &amp;#x22;mydb&amp;#x22;,    &amp;#x22;username&amp;#x22;: &amp;#x22;loige&amp;#x22;,    &amp;#x22;password&amp;#x22;: &amp;#x22;whyDoYouWantToKnowMyPassword&amp;#x22;  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And then to be able to retrieve this data and use it with a new &lt;code&gt;MongoClient&lt;/code&gt; instance:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;MongoClient&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;mongodb&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;MongoClient&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;config&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;mongoConfig&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;mongo&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;MongoClient&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;connect&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;createConnectionString&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;mongoConfig&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;),&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;db&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;var MongoClient = require(&amp;#x27;mongodb&amp;#x27;).MongoClientvar config = require(&amp;#x27;config&amp;#x27;)var mongoConfig = config.get(&amp;#x27;mongo&amp;#x27;)MongoClient.connect(  createConnectionString(mongoConfig),  function(err, db) {    //...  })&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The missing bit here was the function &lt;code&gt;createConnectionString&lt;/code&gt;. How to do that?
I made a quick search on NPM and I wasn’t able to find something ready to be used… So, given that it was a quite easy task and that I enjoy to create new packages, I decided to build it by myself: welcome &lt;strong&gt;&lt;a href=&quot;https://www.npmjs.com/package/mongo-uri-builder&quot;&gt;mongo-uri-builder&lt;/a&gt;&lt;/strong&gt;! &lt;strong&gt;It’s alive!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Frankestain it&amp;amp;#x27;s alive feeling when creating a new NPM library&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;500&quot; height=&quot;276&quot; src=&quot;https://loige.co/_astro/mongodb-connection-string-builder-its-alive-frankestain.C83ixpdm_Fboq6.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;(Yes, this was sort of the feeling I had after launching &lt;code&gt;npm publish&lt;/code&gt;, call me crazy…)&lt;/p&gt;
&lt;h2 id=&quot;the-mongo-uri-builder-package&quot;&gt;The mongo-uri-builder package&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;mongo-uri-builder&lt;/code&gt; is a Node.js package to easily create mongodb connection strings using configuration objects.&lt;/p&gt;
&lt;p&gt;The configuration object that the module expects looks like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;mongoConnectionConfig&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;username&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;user&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// the username&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;pass&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// the password&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;host1&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// the main host (default: &quot;localhost&quot;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1111&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// the main port&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;replicas&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// an array of replica databases&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// every replica must define an host, the port is optional&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;host2&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2222&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;host3&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3333&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;database&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;db&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// the name of the database&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// an arbitrary object of connection options&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;w&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;readPreference&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;secondary&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;var mongoConnectionConfig = {  username: &amp;#x27;user&amp;#x27;, // the username  password: &amp;#x27;pass&amp;#x27;, // the password  host: &amp;#x27;host1&amp;#x27;, // the main host (default: &amp;#x22;localhost&amp;#x22;)  port: 1111, // the main port  replicas: [    // an array of replica databases    // every replica must define an host, the port is optional    { host: &amp;#x27;host2&amp;#x27;, port: 2222 },    { host: &amp;#x27;host3&amp;#x27;, port: 3333 },  ],  database: &amp;#x27;db&amp;#x27;, // the name of the database  options: {    // an arbitrary object of connection options    w: 0,    readPreference: &amp;#x27;secondary&amp;#x27;,  },}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;All the properties are optional and you can even use an empty object. The classic &lt;code&gt;mongodb://localhost&lt;/code&gt; will be generated as default in this case.&lt;/p&gt;
&lt;p&gt;As we are used with NPM, installing the module is as easy as running:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--save&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;mongo-uri-builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install --save mongo-uri-builder&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Then to use it you can do something like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;mongoUriBuilder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;mongo-uri-builder&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;connectionString&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;mongoUriBuilder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;username&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;user&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;pass&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;host1&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1111&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;replicas&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [{ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;host2&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2222&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; }, { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;host3&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3333&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; }],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;database&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;db&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;w&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;readPreference&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;secondary&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;connectionString&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// outputs &quot;mongodb://user:pass@host1:1111,host2:2222,host3:3333/db?w=0&amp;#x26;readPreference=secondary&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;var mongoUriBuilder = require(&amp;#x27;mongo-uri-builder&amp;#x27;)var connectionString = mongoUriBuilder({  username: &amp;#x27;user&amp;#x27;,  password: &amp;#x27;pass&amp;#x27;,  host: &amp;#x27;host1&amp;#x27;,  port: 1111,  replicas: [{ host: &amp;#x27;host2&amp;#x27;, port: 2222 }, { host: &amp;#x27;host3&amp;#x27;, port: 3333 }],  database: &amp;#x27;db&amp;#x27;,  options: {    w: 0,    readPreference: &amp;#x27;secondary&amp;#x27;,  },})console.log(connectionString)// outputs &amp;#x22;mongodb://user:pass@host1:1111,host2:2222,host3:3333/db?w=0&amp;#x26;readPreference=secondary&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;How easy and “well-readable” it is now? :)&lt;/p&gt;
&lt;h2 id=&quot;contributing--issues&quot;&gt;Contributing &amp;#x26; Issues&lt;/h2&gt;
&lt;p&gt;As I often do I put the code of the module on GitHub, you can find the repository at &lt;a href=&quot;https://github.com/lmammino/mongo-uri-builder&quot;&gt;lmammino/mongo-uri-builder&lt;/a&gt;.
Everyone is more than welcome to contribute to the project. You can contribute just by submitting bugs and pull requests or suggesting improvements by &lt;a href=&quot;https://github.com/lmammino/mongo-uri-builder/issues&quot;&gt;opening an issue&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;wrap-up&quot;&gt;Wrap up&lt;/h2&gt;
&lt;p&gt;This module is really something naive but it is a nice thing to have for me, especially in conjunction with &lt;code&gt;config&lt;/code&gt;, that allows me to have different configuration files for every environment (e.g. &lt;code&gt;development&lt;/code&gt; and &lt;code&gt;production&lt;/code&gt;) and to override properties from a &lt;code&gt;default&lt;/code&gt; configuration file.
This way I can just override the parts of the connection string that are effectively different from the default configuration. I can even &lt;a href=&quot;https://github.com/lorenwest/node-config/wiki/Environment-Variables&quot;&gt;use environment variables&lt;/a&gt; if I don’t want for example to store the username and password of my database as clear text in a file.&lt;/p&gt;
&lt;p&gt;I really look forward to knowing what you think about it and if you found it useful. Of course I also hope that you will be willing to give it a spin in your next Node.js project.&lt;/p&gt;
&lt;p&gt;Ah, yeah, if you liked it don’t forget to share the love and “star” it on &lt;a href=&quot;https://github.com/lmammino/mongo-uri-builder&quot;&gt;Github&lt;/a&gt; and &lt;a href=&quot;https://www.npmjs.com/package/mongo-uri-builder&quot;&gt;Npm&lt;/a&gt;! ;)&lt;/p&gt;
&lt;p&gt;Cheers!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/introducing-mongo-uri-builder-a-nodejs-module-to-easily-create-mongodb-connection-strings-using-objects.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/introducing-mongo-uri-builder-a-nodejs-module-to-easily-create-mongodb-connection-strings-using-objects.png" width="1200" height="630"/></media:content><category>node-js</category><category>library</category><category>mongodb</category><category>github</category><author>Luciano Mammino</author><comments>https://loige.co/introducing-mongo-uri-builder-a-nodejs-module-to-easily-create-mongodb-connection-strings-using-objects/#comments</comments><enclosure url="https://loige.co/og/introducing-mongo-uri-builder-a-nodejs-module-to-easily-create-mongodb-connection-strings-using-objects.png" length="0" type="image/png"/></item><item><title>Gulp and FTP: update a website &quot;on the fly&quot;</title><link>https://loige.co/gulp-and-ftp-update-a-website-on-the-fly/</link><guid isPermaLink="true">https://loige.co/gulp-and-ftp-update-a-website-on-the-fly/</guid><description>This tutorial explains how to use Gulp and vinyl-ftp to watch local files for changes and automatically upload updates to a website via FTP. Useful for quickly editing legacy sites only accessible through FTP.</description><pubDate>Sun, 25 Oct 2015 18:47:00 GMT</pubDate><content:encoded>&lt;p&gt;In this post I will explain you how to use &lt;a href=&quot;http://gulpjs.com/&quot;&gt;Gulp&lt;/a&gt; to interact with the files on your server through FTP. You will learn how to watch the files you are editing on your local machine and automatically synchronize them with your server as they change and how to setup a task to launch an FTP deploy on demand.&lt;/p&gt;
&lt;h2 id=&quot;premise&quot;&gt;Premise&lt;/h2&gt;
&lt;p&gt;Few days ago I was assigned to take care of updating few sections on &lt;strong&gt;a legacy website which development environment is currently accessible only through FTP&lt;/strong&gt;. So no local virtualized development environment, no Git, no automated deploy, only old-school “FTP live edit and test”!&lt;/p&gt;
&lt;p&gt;I would have used an FTP desktop app to create a virtual drive to allow me to edit files easily and open the full project in Sublime, but I couldn’t find any good one for the last version of OS X (El Capitan), so I decided to work out a simple solution by myself using Gulp.&lt;/p&gt;
&lt;p&gt;If you ever had a similar situation or if you just want to have a simple and fast command line solution to edit a website you can access to only through FTP, keep reading, this post is for you!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: I just want to stress on the fact that this solution must not be considered a best practice for development and deploy, but only a useful trick in case you have to deal with a very basic setup, especially if you are not in control of the development and deployment environments.&lt;/p&gt;
&lt;h2 id=&quot;installing-gulp&quot;&gt;Installing Gulp&lt;/h2&gt;
&lt;p&gt;In case you don’t know it, Gulp is a very popular build system written in Node.js. It uses streams, so it’s quite efficient in dealing with data transformations and in managing streams of data from different sources.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Gulp is a very popular stream-based build system written in Node.js&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;388&quot; height=&quot;228&quot; src=&quot;https://loige.co/_astro/gulp-is-the-streaming-web-build-system.DVxP-hyb_2cKUn2.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;To be able to run the script we are going to write you need to have Node.js and Gulp installed in your machine. If you don’t have Gulp already you can easily install it with NPM:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-g&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;gulp&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install -g gulp&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;preparing-the-project&quot;&gt;Preparing the project&lt;/h2&gt;
&lt;p&gt;You will need to have a copy of the full project on your local machine, so if you don’t have it already you need to login to your server and download a copy of the source files. You can use any FTP software to do so, but if you are on a Mac there’s a quick trick that allows you to avoid to install any additional software: you can simply open finder and press &lt;code&gt;⌘&lt;/code&gt; + &lt;code&gt;k&lt;/code&gt; to start the &lt;strong&gt;connect to server&lt;/strong&gt; window and specify the FTP url of your project with the following syntax: &lt;code&gt;ftp://username:password@host:port/path&lt;/code&gt;. This will allow you to see and copy all the files from your project and, in case you are wondering, this is a read-only access!&lt;/p&gt;
&lt;p&gt;Once you copied all the files you have to initialize NPM on the copied project with:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;init&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm init&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Follow the on screen instructions and provide all the missing informations.&lt;/p&gt;
&lt;p&gt;Then you need to install Gulp also as a local dependency:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--save-dev&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;gulp&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install --save-dev gulp&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Also we are going to use a couple of external libraries, so let’s install them as well:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--save-dev&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;gulp-util&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;vinyl-ftp&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install --save-dev gulp-util vinyl-ftp&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/gulp-util&quot;&gt;gulp-util&lt;/a&gt; is a module that offers a series of utilities functions for gulp (we will mainly use the log related functions) and &lt;a href=&quot;https://www.npmjs.com/package/vinyl-ftp&quot;&gt;vinyl-ftp&lt;/a&gt; is an FTP library that allows you to access FTP files and folders as streams and it’s a perfect match for Gulp.&lt;/p&gt;
&lt;p&gt;Ok, now the last step before moving to some code is to initialize a new gulp project. To do so just run:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;gulp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;init&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;gulp init&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;It will create a new &lt;code&gt;gulpfile.js&lt;/code&gt; file, let’s finally jump to some code.&lt;/p&gt;
&lt;h2 id=&quot;the-gulpfile&quot;&gt;The gulpfile&lt;/h2&gt;
&lt;p&gt;We are going to implement two different Gulp commands: &lt;code&gt;ftp-deploy&lt;/code&gt; and &lt;code&gt;ftp-deploy-watch&lt;/code&gt;. The first one allows us to deploy all the local changes to the server, the second one instead activates a live watch that constantly monitors our files and uploads immediately any change to the files, very useful when you want to live-code against a development server.&lt;/p&gt;
&lt;p&gt;To enable these two commands you need to copy paste the following code inside your &lt;code&gt;gulpfile.js&lt;/code&gt; file.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;use strict&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;gulp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;gulp&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;gutil&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;gulp-util&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ftp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;vinyl-ftp&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/** Configuration **/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;FTP_USER&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;FTP_PWD&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;your hostname or ip address&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;21&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;localFilesGlob&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;./**/*&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;remoteFolder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/myApp&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// helper function to build an FTP connection based on our configuration&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getFtpConnection&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ftp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;port&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;password&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;parallel&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;gutil&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* Deploy task.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* Copies the new files to the server&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* Usage: `FTP_USER=someuser FTP_PWD=somepwd gulp ftp-deploy`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;gulp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;task&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ftp-deploy&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;conn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getFtpConnection&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;gulp&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;localFilesGlob&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, { &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;base&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;.&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;buffer&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;conn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;newer&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;remoteFolder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// only upload newer files&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;conn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;dest&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;remoteFolder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* Watch deploy task.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* Watches the local copy for changes and copies the new files to the server whenever an update is detected&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;* Usage: `FTP_USER=someuser FTP_PWD=somepwd gulp ftp-deploy-watch`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;gulp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;task&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ftp-deploy-watch&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;conn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getFtpConnection&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;gulp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;watch&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;localFilesGlob&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;).&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;change&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Changes detected! Uploading file &quot;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;&quot;, &apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;type&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;gulp&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#885D01&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;], { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;base&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;.&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;buffer&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;conn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;newer&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;remoteFolder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// only upload newer files&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;conn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;dest&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;remoteFolder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&amp;#x27;use strict&amp;#x27;var gulp = require(&amp;#x27;gulp&amp;#x27;)var gutil = require(&amp;#x27;gulp-util&amp;#x27;)var ftp = require(&amp;#x27;vinyl-ftp&amp;#x27;)/** Configuration **/var user = process.env.FTP_USERvar password = process.env.FTP_PWDvar host = &amp;#x27;your hostname or ip address&amp;#x27;var port = 21var localFilesGlob = [&amp;#x27;./**/*&amp;#x27;]var remoteFolder = &amp;#x27;/myApp&amp;#x27;// helper function to build an FTP connection based on our configurationfunction getFtpConnection() {  return ftp.create({    host: host,    port: port,    user: user,    password: password,    parallel: 5,    log: gutil.log,  })}/** * Deploy task. * Copies the new files to the server * * Usage: &amp;#x60;FTP_USER=someuser FTP_PWD=somepwd gulp ftp-deploy&amp;#x60; */gulp.task(&amp;#x27;ftp-deploy&amp;#x27;, function() {  var conn = getFtpConnection()  return gulp    .src(localFilesGlob, { base: &amp;#x27;.&amp;#x27;, buffer: false })    .pipe(conn.newer(remoteFolder)) // only upload newer files    .pipe(conn.dest(remoteFolder))})/** * Watch deploy task. * Watches the local copy for changes and copies the new files to the server whenever an update is detected * * Usage: &amp;#x60;FTP_USER=someuser FTP_PWD=somepwd gulp ftp-deploy-watch&amp;#x60; */gulp.task(&amp;#x27;ftp-deploy-watch&amp;#x27;, function() {  var conn = getFtpConnection()  gulp.watch(localFilesGlob).on(&amp;#x27;change&amp;#x27;, function(event) {    console.log(      &amp;#x27;Changes detected! Uploading file &amp;#x22;&amp;#x27; + event.path + &amp;#x27;&amp;#x22;, &amp;#x27; + event.type    )    return gulp      .src([event.path], { base: &amp;#x27;.&amp;#x27;, buffer: false })      .pipe(conn.newer(remoteFolder)) // only upload newer files      .pipe(conn.dest(remoteFolder))  })})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The Gulp script is very simple and pretty self-descriptive, but let’s try to have a look at it in greater detail.&lt;/p&gt;
&lt;p&gt;After importing our modules, we have a series of configuration variables. The ones you have to set are &lt;code&gt;host&lt;/code&gt;, &lt;code&gt;port&lt;/code&gt;, &lt;code&gt;localFilesGlob&lt;/code&gt; and &lt;code&gt;remoteFolder&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;host&lt;/code&gt; is the hostname or the IP address of your FTP server (e.g. &lt;code&gt;myserver.com&lt;/code&gt; or &lt;code&gt;123.124.125.126&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;port&lt;/code&gt; is the port where your FTP server is listening (generally it’s the default: &lt;code&gt;21&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;localFilesGlob&lt;/code&gt; is an array containing one or more &lt;a href=&quot;https://www.npmjs.com/package/glob&quot;&gt;glob&lt;/a&gt; expressions. These expressions are used to determine which files from your local copy should be watched and deployed into the server. The default option is very “open”, it will copy all the files in your project folder. Most of the time it’s better to be more specific so, be sure to build your own custom array of glob to avoid copying unnecessary or sensible data.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;remoteFolder&lt;/code&gt; is the folder in your remote server that contains the whole project (where the new files will be copied).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you probably noticed we also have the &lt;code&gt;username&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt; variables mapped to an environment variable. Is generally a good idea to not write passwords in configuration files, especially if you are going to publish this file somewhere. With this approach we can also share the same gulpfile with other people in the team and allow everyone to use their personal credentials.&lt;/p&gt;
&lt;p&gt;After the configuration variables block we have the &lt;code&gt;getFtpConnection&lt;/code&gt; function. This function is used as an helper to build an FTP connection using the previously specified options. You can also add some &lt;a href=&quot;https://www.npmjs.com/package/vinyl-ftp#ftp-create-config&quot;&gt;additional options&lt;/a&gt;, for instance &lt;code&gt;parallel&lt;/code&gt; allows you to define the maximum number of files to upload in parallel.&lt;/p&gt;
&lt;p&gt;At the end we have our two real Gulp commands: &lt;code&gt;ftp-deploy&lt;/code&gt; and &lt;code&gt;ftp-deploy-watch&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;They simply defines a stream starting from the glob expressions and pipe it to the destination server through the FTP connection. The only difference between the two commands is that in the &lt;code&gt;ftp-deploy&lt;/code&gt; we read all the files from the glob expressions and send them through the connection, in the second case we watch the files and send only the one that changes while command is running.&lt;/p&gt;
&lt;p&gt;It’s also worth noticing that we are piping the files through the function &lt;code&gt;conn.newer&lt;/code&gt;. This function ensures that only the files that are different from the server gets overwritten.&lt;/p&gt;
&lt;h2 id=&quot;running-the-commands&quot;&gt;Running the commands&lt;/h2&gt;
&lt;p&gt;To run the commands you must first specify the &lt;code&gt;FTP_USER&lt;/code&gt; and &lt;code&gt;FTP_PWD&lt;/code&gt; environment variables. For example you can do it this way:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;FTP_USER&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;someuser&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;FTP_PWD&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;somepwd&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;gulp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;ftp-deploy&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;FTP_USER=someuser FTP_PWD=somepwd gulp ftp-deploy&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;FTP_USER&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;someuser&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;FTP_PWD&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;somepwd&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;gulp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;ftp-deploy-watch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;FTP_USER=someuser FTP_PWD=somepwd gulp ftp-deploy-watch&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Or if you prefer you can export the variables in your &lt;code&gt;.bashrc&lt;/code&gt; or &lt;code&gt;.bash_profile&lt;/code&gt; files (in this case I suggest you to rename the variables into something more specific to avoid collisions).&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;This approach allowed me to solve the problem easily and quickly having a mechanism that is quite fast to use and easy to maintain.&lt;/p&gt;
&lt;p&gt;I am also more and more impressed about how easy is to have simple but effective solutions up and running with Node.js and the tools in its ecosystem. I am also impressed by the versatility of Gulp and how its stream-based approach makes things very concise and uniform.&lt;/p&gt;
&lt;p&gt;I hope this article was useful and interesting for you.
I’d really love to receive &lt;strong&gt;your opinions in the comments box&lt;/strong&gt; about it and, in case you are a veteran Gulp user, I’m curious to know &lt;strong&gt;what was the most interesting command you have ever written using Gulp&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Until next time!&lt;/p&gt;
&lt;p&gt;Regards&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/gulp-and-ftp-update-a-website-on-the-fly.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/gulp-and-ftp-update-a-website-on-the-fly.png" width="1200" height="630"/></media:content><category>gulp</category><category>javascript</category><category>ftp</category><category>server</category><author>Luciano Mammino</author><comments>https://loige.co/gulp-and-ftp-update-a-website-on-the-fly/#comments</comments><enclosure url="https://loige.co/og/gulp-and-ftp-update-a-website-on-the-fly.png" length="0" type="image/png"/></item><item><title>Introducing Gulp cozy - Manage your gulp tasks in a cozier way</title><link>https://loige.co/introducing-gulp-cozy-manage-your-gulp-tasks-in-a-cozier-way/</link><guid isPermaLink="true">https://loige.co/introducing-gulp-cozy-manage-your-gulp-tasks-in-a-cozier-way/</guid><description>Gulp-cozy is an experimental NPM package that allows you to separate Gulp tasks into small modules inside a dedicated folder, making them easier to maintain. It brings Node.js modularity principles into your Gulp workflow.</description><pubDate>Mon, 18 Jan 2016 23:27:40 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/gulp-cozy&quot;&gt;Gulp-cozy&lt;/a&gt; is an experimental NPM package that allows you to organize your Gulp tasks in a more modular way with simplicity and &lt;em&gt;“cozyness”&lt;/em&gt; in mind.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;I don&amp;amp;#x27;t always modularize my gulp tasks, but when I do it must be cozy!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;500&quot; height=&quot;627&quot; src=&quot;https://loige.co/_astro/gulp-cozy-i-dont-always-loige-luciano-mammino.Dbh_FDxp_GypvK.webp&quot; &gt;&lt;/p&gt;
&lt;h2 id=&quot;rationale&quot;&gt;Rationale&lt;/h2&gt;
&lt;p&gt;Ever found yourself digging into a gigantic monstrous &lt;code&gt;Gulpfile&lt;/code&gt; with hundreds
of functions and tasks scattered all around? If it happened to you I am sure you can tell that it’s not a great feeling…&lt;/p&gt;
&lt;p&gt;That’s the reason why I created this small module as an attempt to help with keeping yourself cozier (and happier!) when working with Gulp.
In a way it tries to bring a bit of the &lt;em&gt;Node philosophy&lt;/em&gt; (also known as “&lt;a href=&quot;http://thenodeway.io/&quot;&gt;The Node way&lt;/a&gt;”) into your Gulpfile.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Gulp-cozy&lt;/em&gt; in fact offers a very easy way (read: &lt;em&gt;very-very-very-easy!&lt;/em&gt;) to separate all your Gulp tasks into small modules organized inside a dedicated folder. Gulp-cozy will take care to load all the modules and to register them as Gulp tasks. With this approach you will end up with several small modules that serve one specific purpose (a task), which in turn result easier to maintain and to reason about.&lt;/p&gt;
&lt;h2 id=&quot;installation-and-usage&quot;&gt;Installation and usage&lt;/h2&gt;
&lt;p&gt;Enough talking, let’s jump to the practice! As most of the NPM packages to install &lt;code&gt;gulp-cozy&lt;/code&gt; you just need to run the following command inside your project folder:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--save-dev&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;gulp-cozy&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm install --save-dev gulp-cozy&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Of course I am assuming you have already installed &lt;code&gt;Gulp&lt;/code&gt; globally and as local dev dependency for your project.&lt;/p&gt;
&lt;p&gt;Once NPM finished downloading (it should be fast, the module is pretty small!) you can turn you &lt;code&gt;Gulpfile.js&lt;/code&gt; into this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Gulpfile.js&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;gulp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;gulp&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;cozy&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;gulp-cozy&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;cozy&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;gulp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;var gulp = require(&amp;#x27;gulp&amp;#x27;);var cozy = require(&amp;#x27;gulp-cozy&amp;#x27;);cozy(gulp);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;YES! This will be the only content of your Gulpfile…
So you might ask &lt;em&gt;“where do all the tasks logic go?”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The idea is to keep all the tasks inside a &lt;code&gt;gulp&lt;/code&gt; folder in your main project folder (doesn’t it make you think to the &lt;code&gt;node_modules&lt;/code&gt; folder approach?!). Every task is a file which name will represent the name of the gulp task.&lt;/p&gt;
&lt;p&gt;Don’t worry too much for now, let’s just create this new &lt;code&gt;gulp&lt;/code&gt; folder and everything will be cleaner in a moment with a more practical example.&lt;/p&gt;
&lt;p&gt;Let’s assume we want to create a new task to build the css files for our new project. For this sake we can add the &lt;code&gt;build-css&lt;/code&gt; task by creating the &lt;code&gt;build-css.js&lt;/code&gt; file as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;gulp/build-css.js&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;concat&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;gulp-concat&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;minifyCss&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;gulp-minify-css&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#AF4238&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#AF4238&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;gulp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;gulp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;([&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;./node_modules/bootstrap/dist/css/bootstrap.css&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;])&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;concat&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;all.css&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;minifyCss&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;compatibility&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ie8&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;pipe&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;gulp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;dest&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;./assets/&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;var concat = require(&amp;#x27;gulp-concat&amp;#x27;);var minifyCss = require(&amp;#x27;gulp-minify-css&amp;#x27;);module.exports = function(gulp) {  return function() {    return gulp.src([      &amp;#x27;./node_modules/bootstrap/dist/css/bootstrap.css&amp;#x27;    ])      .pipe(concat(&amp;#x27;all.css&amp;#x27;))      .pipe(minifyCss({compatibility: &amp;#x27;ie8&amp;#x27;}))      .pipe(gulp.dest(&amp;#x27;./assets/&amp;#x27;))    ;  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Notice that the module exports a function that receives the current instance of Gulp as argument. This function is a factory for the real Gulp task logic so it should return a function which, will be executed when calling the &lt;code&gt;build-css&lt;/code&gt; task with:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;gulp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;build-css&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;gulp build-css&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;You can also create a module to call a series tasks as in the following
example.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;gulp/build.js&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#AF4238&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#AF4238&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;clean&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;build-css&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;build-js&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;compress&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;upload&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;module.exports = [&amp;#x27;clean&amp;#x27;, &amp;#x27;build-css&amp;#x27;, &amp;#x27;build-js&amp;#x27;, &amp;#x27;compress&amp;#x27;, &amp;#x27;upload&amp;#x27;];&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In this case, rather than using a factory function, the module needs to export just a plain array containing the names of the tasks to be invoked. You can launch this new task with:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;gulp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;gulp build&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;What do you think? Doesn’t it make things more separated, organised and most importantly “cozy”?&lt;/p&gt;
&lt;h2 id=&quot;long-way-to-perfection&quot;&gt;Long way to perfection&lt;/h2&gt;
&lt;p&gt;As I told in the very first line this approach has to be considered &lt;strong&gt;experimental&lt;/strong&gt; for now and there are still many concerns that I have about it.&lt;/p&gt;
&lt;p&gt;First of all the module tries to expose a very small surface and to do one simple thing. That’s generally good and it sticks to the node philosophy. But at the same time it’s probably not very flexible.&lt;/p&gt;
&lt;p&gt;Would be great to have a way to define generic task templates, like for example processing CSS files (compile from sass, concatenate and minify) and than have a configurable way to use this template with different sets of files and producing different assets.&lt;/p&gt;
&lt;p&gt;At the moment you could do this by creating a generic configurable module outside your &lt;code&gt;gulp&lt;/code&gt; folder and than require it and use it inside one or more tasks in the new folder. This approach should work without big efforts but doesn’t feel very right to me at the moment.&lt;/p&gt;
&lt;p&gt;Probably the module should expose more functions to deal with more complex case, but it boils down to the eternal struggle between “keeping things simple” and “making the new jack-of-all-trades module”…&lt;/p&gt;
&lt;h2 id=&quot;contributing&quot;&gt;Contributing&lt;/h2&gt;
&lt;p&gt;If you want to contribute to this project you can find the sources on &lt;a href=&quot;https://github.com/lmammino/gulp-cozy&quot;&gt;GitHub&lt;/a&gt; (of course!). If this project is interesting to you you are very welcome to contribute by submitting a pull request or simply by &lt;a href=&quot;https://github.com/lmammino/gulp-cozy/issues&quot;&gt;opening an issue&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you decide to go with the pull request, please take care to maintain the existing coding style and add unit tests for any new or changed functionality.
The project is currently using &lt;a href=&quot;https://github.com/sindresorhus/xo&quot;&gt;XO&lt;/a&gt; for styleguide and style checks run with the regular test suite.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I am really curious to see if this topic and this library can be of any interest for other people. I’d like to know if you ever questioned yourself to find better solutions to organize your Gulp tasks and if you came out with some kind of personal solution. I would be very happy to see some comments down this article, maybe a nice discussion might born from this.&lt;/p&gt;
&lt;p&gt;Before leaving you I have to thank my dearest friend &lt;a href=&quot;https://www.linkedin.com/in/manganoandrea&quot;&gt;Andrea&lt;/a&gt; for discussing these topics and give me the inspiration to spend some time on this subject.&lt;/p&gt;
&lt;p&gt;Until next time! :)&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/introducing-gulp-cozy-manage-your-gulp-tasks-in-a-cozier-way.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/introducing-gulp-cozy-manage-your-gulp-tasks-in-a-cozier-way.png" width="1200" height="630"/></media:content><category>gulp</category><category>javascript</category><category>node-js</category><category>library</category><author>Luciano Mammino</author><comments>https://loige.co/introducing-gulp-cozy-manage-your-gulp-tasks-in-a-cozier-way/#comments</comments><enclosure url="https://loige.co/og/introducing-gulp-cozy-manage-your-gulp-tasks-in-a-cozier-way.png" length="0" type="image/png"/></item><item><title>Get an invitation for GitKraken</title><link>https://loige.co/get-an-invitation-for-gitkraken/</link><guid isPermaLink="true">https://loige.co/get-an-invitation-for-gitkraken/</guid><description>GitKraken is a new cross-platform graphical interface for Git currently in private beta. It has useful features like interactive commit graph visualization, easy branching/stashing, and GitHub integration. The post shares invites to try the private beta version of GitKraken.</description><pubDate>Tue, 19 Jan 2016 21:10:23 GMT</pubDate><content:encoded>&lt;p&gt;Axosoft is currently working on &lt;a href=&quot;http://www.gitkraken.com/&quot;&gt;GitKraken&lt;/a&gt; an
innovative multi-platform graphical client for &lt;a href=&quot;/tag/git&quot;&gt;git&lt;/a&gt; which is already
available for Windows, Linux and Mac OSX in &lt;strong&gt;private beta&lt;/strong&gt; version.&lt;/p&gt;
&lt;p&gt;The private beta is accessible through an invite code. I was lucky to get an
invite for me and &lt;strong&gt;&lt;del&gt;I have&lt;/del&gt; some extra invites that I am willing to share
with the first people who is going to leave a comment on this post&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;UPDATE &lt;strong&gt;2016-01-19 22:00 GMT&lt;/strong&gt;: I finished all the invites in less than 1
hour! That’s incredible :O Sorry for whoever remained out, I’ll let you know
if I manage to get more invites!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UPDATE &lt;strong&gt;2016-01-19 23:00 GMT&lt;/strong&gt;: Seems that I was very very lucky and I got
some &lt;strong&gt;NEW INVITES&lt;/strong&gt;, keep commenting to get them! ;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UPDATE &lt;strong&gt;2016-01-23 09:00 GMT&lt;/strong&gt;: Invites are over!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UPDATE &lt;strong&gt;2016-02-03 18:50 GMT&lt;/strong&gt;: Yesterday GitKraken 0.6 was released as
Public Beta and it’s free to be downloaded on the
&lt;a href=&quot;http://www.gitkraken.com/&quot;&gt;official website&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-is-gitkraken&quot;&gt;What is GitKraken&lt;/h2&gt;
&lt;p&gt;As I said, GitKraken is a new &lt;em&gt;shiny&lt;/em&gt; graphical interface for &lt;a href=&quot;/tag/git&quot;&gt;git&lt;/a&gt;. I
am a big fan of git from command line and even if I used a number of different
GUIs in the past I always switched back to the console. By the way, GitKraken
looks promising thanks to a set of interesting features. Let’s have a look at
the ones that impressed me most after a first try.&lt;/p&gt;
&lt;h3 id=&quot;network-view&quot;&gt;Network view&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;GitKraken network view branching model graph&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;1806&quot; src=&quot;https://loige.co/_astro/gitkraken-network-view-loige-co-luciano-mammino-big.Bke4pJqs_xD4NT.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;This is probably the &lt;strong&gt;killer feature&lt;/strong&gt; at the moment, a &lt;em&gt;nice-looking&lt;/em&gt;
graphical view of your git network that allows you to understand what is the
current status of you repository in terms of commits and branches. Every dot in
the graph represents a commit and it is interactive. When you select one of them
you can see all the changes applied by that commit, who pushed it, the commit
description and, most importantly, if you right click on it you can immediately
perform a number of actions which are notoriously not so trivial from the
command line:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cherry-pick&lt;/li&gt;
&lt;li&gt;create a branch from the specific commit&lt;/li&gt;
&lt;li&gt;create a new tag pointing that commit&lt;/li&gt;
&lt;li&gt;reset master to that commit&lt;/li&gt;
&lt;li&gt;edit commit message&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;integration-with-github&quot;&gt;Integration with &lt;a href=&quot;/tag/github&quot;&gt;GitHub&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;GitKraken integration with GitHub&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3024&quot; height=&quot;1806&quot; src=&quot;https://loige.co/_astro/gitkraken-github-integration-loige-co-luciano-mammino-big.BpoLGVAV_Z2cimn4.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;GitKraken allows you to connect with your GitHub social account and easily
access and clone from your remote repositories or fork an existing repository.&lt;/p&gt;
&lt;p&gt;This is a lovely feature that will save you some amount of time if you are an
active open source contributor or if your organisation is using GitHub for
business.&lt;/p&gt;
&lt;p&gt;The integration is currently limited to cloning, but I hope it will be improved
to support also pull requests and issues (which would be definitely amazing!).&lt;/p&gt;
&lt;p&gt;Also it’s worth mentioning that the support for BitBucket seems to be coming
soon!&lt;/p&gt;
&lt;h3 id=&quot;branching-and-stashing&quot;&gt;Branching and Stashing&lt;/h3&gt;
&lt;p&gt;There are a couple of other interesting operations that are made trivial by
GitKraken… I am talking about &lt;strong&gt;branching&lt;/strong&gt; and &lt;strong&gt;stashing&lt;/strong&gt;. By just clicking
a button you will be able to create a new branch starting from the current head
or from a specific commit and you can also &lt;em&gt;stash&lt;/em&gt; your current &lt;em&gt;uncommitted&lt;/em&gt;
changes. When you stash something you will see a dot in your network graph that
represents the stashed data as if it was a commit and you will be able to
&lt;em&gt;unstash&lt;/em&gt; that changes at any time later in the future. Personally I believe
these features can simplify the adoption of a Git branching model as
&lt;a href=&quot;http://nvie.com/posts/a-successful-git-branching-model/&quot;&gt;GitFlow&lt;/a&gt; within your
team.&lt;/p&gt;
&lt;h3 id=&quot;built-with-electron-and-nodejs&quot;&gt;Built with &lt;a href=&quot;http://electron.atom.io/&quot;&gt;Electron&lt;/a&gt; and &lt;a href=&quot;/tag/node-js&quot;&gt;Node.js&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While this is not a big differentiator at the moment (apart from making it
immediately cross platform), I am quite sure that this feature will allow
GitKraken to offer a nice extensibility layer offering people a way to write
their own plugins/integrations. Just look at recent softwares like
&lt;a href=&quot;https://github.com/nylas/N1&quot;&gt;nylan/N1&lt;/a&gt; and
&lt;a href=&quot;/3-invitations-to-try-atom-io/&quot;&gt;Atom&lt;/a&gt; to understand what is possible with this
technology and why developers are loving these products.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I think it’s still to early to form a strong opinion about this product, but the
premises are excellent and I would say we can expect great things for the first
public release. I hope Axosoft will decide to keep it free as Atlassian is doing
with SourceTree and that this choice might be another incentive to allow people
to adopt or get even more familiar with Git.&lt;/p&gt;
&lt;p&gt;I am curious to know your opinion about it and if you prefer to use a GUI rather
than the command line, so please leave a comment.&lt;/p&gt;
&lt;p&gt;Also remember to &lt;del&gt;leave a comment down below this post if you need an
invitation to try it&lt;/del&gt; (invites over)!&lt;/p&gt;
&lt;p&gt;Until next time :)&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/get-an-invitation-for-gitkraken.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/get-an-invitation-for-gitkraken.png" width="1200" height="630"/></media:content><category>git</category><category>github</category><author>Luciano Mammino</author><comments>https://loige.co/get-an-invitation-for-gitkraken/#comments</comments><enclosure url="https://loige.co/og/get-an-invitation-for-gitkraken.png" length="0" type="image/png"/></item><item><title>6 Tips to Build Fast Web Applications (Php Dublin March 2016 Talk)</title><link>https://loige.co/6-tips-to-build-fast-web-applications-php-dublin-march-2016-talk/</link><guid isPermaLink="true">https://loige.co/6-tips-to-build-fast-web-applications-php-dublin-march-2016-talk/</guid><description>This post shares 6 tips to build fast web applications based on a talk at Php Dublin in March 2016. It includes slides and covers topics like caching, compression, database optimization, and more.</description><pubDate>Wed, 23 Mar 2016 09:16:00 GMT</pubDate><content:encoded>&lt;p&gt;Following one of my previous posts about &lt;a href=&quot;http://loige.co/6-rules-of-thumb-to-build-blazing-fast-web-applications/&quot;&gt;performance in web applications&lt;/a&gt;, yesterday night I had the chance to give a related talk at the &lt;a href=&quot;https://phpdublin.com/&quot;&gt;Php Dublin user group&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My talk was preceded by a great talk (and demo) by &lt;strong&gt;Ricardo Melo&lt;/strong&gt; (&lt;a href=&quot;https://twitter.com/rjsmelo&quot;&gt;@rjsmelo&lt;/a&gt;) called &lt;a href=&quot;http://www.slideshare.net/rjsmelo/docker-php-practical-use-case&quot;&gt;Docker and Php, a practical use case&lt;/a&gt;. If you are interested in the topic, be sure to check it out!&lt;/p&gt;
&lt;p&gt;It was a great night, I learned a lot and I had a lot of fun, so thank you to everyone involved.&lt;/p&gt;
&lt;p&gt;If you are interested in having a look at the slides, here they are:&lt;/p&gt;
&lt;iframe src=&quot;//slides.com/lucianomammino/6tips-web-perf/embed&quot; width=&quot;576&quot; height=&quot;420&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;a href=&quot;//slides.com/lucianomammino/6tips-web-perf&quot;&gt;http://slides.com/lucianomammino/6tips-web-perf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Feel free to leave your opinion in the comments.&lt;/p&gt;
&lt;p&gt;Cheers!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/6-tips-to-build-fast-web-applications-php-dublin-march-2016-talk.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/6-tips-to-build-fast-web-applications-php-dublin-march-2016-talk.png" width="1200" height="630"/></media:content><category>php</category><category>slides</category><category>talk</category><category>performance</category><author>Luciano Mammino</author><comments>https://loige.co/6-tips-to-build-fast-web-applications-php-dublin-march-2016-talk/#comments</comments><enclosure url="https://loige.co/og/6-tips-to-build-fast-web-applications-php-dublin-march-2016-talk.png" length="0" type="image/png"/></item><item><title>Extracting data from Wikipedia using curl, grep, cut and other shell commands</title><link>https://loige.co/extracting-data-from-wikipedia-using-curl-grep-cut-and-other-bash-commands/</link><guid isPermaLink="true">https://loige.co/extracting-data-from-wikipedia-using-curl-grep-cut-and-other-bash-commands/</guid><description>By using a combination of curl, grep, cut, sort, uniq and other common bash utilities it is possible to extract structured data from Wikipedia and compute insights without writing a full program.</description><pubDate>Mon, 15 Aug 2016 17:17:00 GMT</pubDate><content:encoded>&lt;p&gt;In this article I am going to show you how I was able to extract and process some information from Wikipedia only using a combination of common bash utilities like &lt;code&gt;curl&lt;/code&gt; and &lt;code&gt;grep&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-need&quot;&gt;The need&lt;/h2&gt;
&lt;p&gt;If you are a sport lover like me I guess your heart is currently being warmed by the &lt;strong&gt;Rio 2016 Olympic games&lt;/strong&gt;. My favourite sport in the games is &lt;strong&gt;Judo&lt;/strong&gt; and now that the competitions are over I was wondering who were &lt;strong&gt;the best olympic “judokas” of all the times&lt;/strong&gt; by number of medals collected during the games (no matter the kind of medal).
I tried to &lt;em&gt;google&lt;/em&gt; the answer for a while but it wasn’t easy to find an up to date result, so I decided to do some quick research and trying to get to a conclusion by myself. I have to say it was I bit tougher than I expected, but it was definitively fun…&lt;/p&gt;
&lt;h2 id=&quot;the-dataset&quot;&gt;The dataset&lt;/h2&gt;
&lt;p&gt;The first thing I needed was a reliable and up to date data source listing all the Judo Olympic medal winners in history. This was easy to find on Wikipedia: &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_Olympic_medalists_in_judo&quot;&gt;List of Olympic medalists in Judo&lt;/a&gt;.
Anyway the data on this Wikipedia page is structured to be easy to read by humans and not to be processed by a machine. Also I didn’t found any way to have the same data in the page in a &lt;em&gt;csv&lt;/em&gt; or &lt;em&gt;json&lt;/em&gt; format, so the only viable option was to extract the data by myself from the web page.
At first I thought about creating a quick and dirty &lt;a href=&quot;/tag/javascript&quot;&gt;JavaScript&lt;/a&gt; command and use some library like &lt;a href=&quot;https://cheerio.js.org&quot;&gt;cheerio&lt;/a&gt; to extract the data directly from the HTML code of the page, but it sounded like to much of work for the simple goal I had in mind.
So I had another quick look at Wikipedia to find out if there was any better format to extract the information. Going to the &lt;em&gt;edit&lt;/em&gt; option of the page I realized that parsing the &lt;a href=&quot;https://www.mediawiki.org/wiki/Markup_spec&quot;&gt;wikitext&lt;/a&gt; (source) of the page would have been much easier and I could even use a regular expression to extract the relevant information from there.
At this stage I wondered if there was a way to get only the wikitext of a specific Wikipedia page. It turns out that it’s possible and it’s very easy: you just need to append the query parameter &lt;code&gt;?action=raw&lt;/code&gt; in the url!&lt;/p&gt;
&lt;p&gt;So hitting &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_Olympic_medalists_in_judo?action=raw&quot;&gt;https://en.wikipedia.org/wiki/List_of_Olympic_medalists_in_judo?action=raw&lt;/a&gt; will give us our starting dataset which will look like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;==Men==&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;===Extra Lightweight===&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;*60&amp;#x26;nbsp;kg&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;{| {{MedalistTable|type=Games}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|-&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|rowspan=2|[[Judo at the 1980 Summer Olympics|1980 Moscow]]&amp;#x3C;br&gt;{{DetailsLink|Judo at the 1980 Summer Olympics – Men&apos;s 60 kg}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|rowspan=2|{{flagIOCmedalist|[[Thierry Rey]]|FRA|1980 Summer}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|rowspan=2|{{flagIOCmedalist|[[José Rodríguez (judoka)|José Rodríguez]]|CUB|1980 Summer}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|{{flagIOCmedalist|[[Tibor Kincses (judoka)|Tibor Kincses]]|HUN|1980 Summer}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|-&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|{{flagIOCmedalist|[[Aramby Emizh]]|URS|1980 Summer}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|-&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|rowspan=2|[[Judo at the 1984 Summer Olympics|1984 Los Angeles]]&amp;#x3C;br&gt;{{DetailsLink|Judo at the 1984 Summer Olympics – Men&apos;s 60 kg}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|rowspan=2|{{flagIOCmedalist|[[Shinji Hosokawa]]|JPN|1984 Summer}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|rowspan=2|{{flagIOCmedalist|[[Kim Jae-Yup]]|KOR|1984 Summer}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|{{flagIOCmedalist|[[Neil Eckersley]]|GBR|1984 Summer}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|-&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|{{flagIOCmedalist|[[Edward Liddie]]|USA|1984 Summer}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|-&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;==Men=====Extra Lightweight===*60&amp;#x26;nbsp;kg{| {{MedalistTable|type=Games}}|-|rowspan=2|[[Judo at the 1980 Summer Olympics|1980 Moscow]]&lt;br&gt;{{DetailsLink|Judo at the 1980 Summer Olympics – Men&amp;#x27;s 60 kg}}|rowspan=2|{{flagIOCmedalist|[[Thierry Rey]]|FRA|1980 Summer}}|rowspan=2|{{flagIOCmedalist|[[José Rodríguez (judoka)|José Rodríguez]]|CUB|1980 Summer}}|{{flagIOCmedalist|[[Tibor Kincses (judoka)|Tibor Kincses]]|HUN|1980 Summer}}|-|{{flagIOCmedalist|[[Aramby Emizh]]|URS|1980 Summer}}|-|rowspan=2|[[Judo at the 1984 Summer Olympics|1984 Los Angeles]]&lt;br&gt;{{DetailsLink|Judo at the 1984 Summer Olympics – Men&amp;#x27;s 60 kg}}|rowspan=2|{{flagIOCmedalist|[[Shinji Hosokawa]]|JPN|1984 Summer}}|rowspan=2|{{flagIOCmedalist|[[Kim Jae-Yup]]|KOR|1984 Summer}}|{{flagIOCmedalist|[[Neil Eckersley]]|GBR|1984 Summer}}|-|{{flagIOCmedalist|[[Edward Liddie]]|USA|1984 Summer}}|-...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note that, for the sake of brevity, from now on I will use &lt;code&gt;...&lt;/code&gt; to indicates that there’s a lot of data that was stripped from the example.&lt;/p&gt;
&lt;p&gt;We can easily get this data into our bash shell with &lt;code&gt;curl&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-sS&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;https://en.wikipedia.org/wiki/List_of_Olympic_medalists_in_judo?action=raw&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;curl -sS &amp;#x22;https://en.wikipedia.org/wiki/List_of_Olympic_medalists_in_judo?action=raw&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In case you don’t know the options &lt;code&gt;-sS&lt;/code&gt; allow to strip out the download progress output and just print the downloaded data (or any possible error) in the console.&lt;/p&gt;
&lt;p&gt;Now that we have our dataset, to compute the result we need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Extract all the athletes names&lt;/li&gt;
&lt;li&gt;Count the occurrences of each one of them&lt;/li&gt;
&lt;li&gt;Reverse order them by the resulting count.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We will do so with a combination of bash commands, bound together using the pipe operator (&lt;code&gt;|&lt;/code&gt;). Pipes let you use the output of a program as the input of another one, effectively creating a stream of data that is transformed step by step by small and easy to understand operations.&lt;/p&gt;
&lt;h2 id=&quot;extracting-data-with-grep&quot;&gt;Extracting data with &lt;code&gt;grep&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The dataset shown before is just the wikitext code needed to render the tables of athletes that won medals by category and year. So we can easily assume that all the athletes listed in the page are interesting for us.&lt;/p&gt;
&lt;p&gt;As you can see every athlete is referenced in the code using the &lt;em&gt;template&lt;/em&gt; &lt;code&gt;flagIOCmedalist&lt;/code&gt; and every entry looks like:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;{{flagIOCmedalist|[[NAME]]|COUNTRY|OLYMPIC GAME}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{{flagIOCmedalist|[[NAME]]|COUNTRY|OLYMPIC GAME}}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;So we can easily extract all the athletes names with a regex like the following:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;flagIOCmedalist\|\[\[(.+)\]\]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;flagIOCmedalist\|\[\[(.+)\]\]&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This regular expression behaves as described in the following picture:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;flagIOCmedalist matches the characters flagIOCmedalist literally&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1192&quot; height=&quot;364&quot; src=&quot;https://loige.co/_astro/flagIOCmedalist_matches_the_characters_flagIOCmedalist.CrHrvAHq_ZzbUas.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;If you want to understand all the details of this regex you can play with it on &lt;a href=&quot;https://regex101.com/r/cT7nD8/2&quot;&gt;regex101&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the shell we can apply a regex to an input data using &lt;code&gt;grep&lt;/code&gt;. We need to concatenate the output of &lt;code&gt;curl&lt;/code&gt; to &lt;code&gt;grep&lt;/code&gt; using the pipe operator (&lt;code&gt;|&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; |  &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-Eoi&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;flagIOCmedalist\|\[\[(.+)\]\]&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;curl ... |  grep -Eoi &amp;#x22;flagIOCmedalist\|\[\[(.+)\]\]&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;With the &lt;code&gt;grep&lt;/code&gt; we are using the options &lt;code&gt;-Eoi&lt;/code&gt; which allow us to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-E&lt;/code&gt;: use a POSIX &lt;em&gt;extended&lt;/em&gt; regular expression (&lt;a href=&quot;https://en.wikibooks.org/wiki/Regular_Expressions/POSIX-Extended_Regular_Expressions&quot;&gt;ERE&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-o&lt;/code&gt;: print only the matched (non-empty) parts of a matching line&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i&lt;/code&gt;: case insensitive matching (this is not really needed for our problem, but could allow us to match any case variation of the template reference like &lt;code&gt;flagiocmedalist&lt;/code&gt; and &lt;code&gt;FLAGIOCMEDALIST&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The previous command is going to output something like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;flagIOCmedalist|[[Thierry Rey]]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;flagIOCmedalist|[[José Rodríguez (judoka)|José Rodríguez]]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;flagIOCmedalist|[[Tibor Kincses (judoka)|Tibor Kincses]]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;flagIOCmedalist|[[Aramby Emizh]]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;flagIOCmedalist|[[Thierry Rey]]flagIOCmedalist|[[José Rodríguez (judoka)|José Rodríguez]]flagIOCmedalist|[[Tibor Kincses (judoka)|Tibor Kincses]]flagIOCmedalist|[[Aramby Emizh]]...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Which, of course, looks kind of ugly. We ideally want to have only the name of every athlete and not all the &lt;code&gt;template&lt;/code&gt; syntax wrapping it.&lt;/p&gt;
&lt;p&gt;Let’s try to clean up the data a little bit more.&lt;/p&gt;
&lt;h2 id=&quot;cleaning-up-the-data-with-cut&quot;&gt;Cleaning up the data with &lt;code&gt;cut&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;cut&lt;/code&gt; is another interesting command line utility that can be used in a whole lot of different ways to extract substrings (or columns) from text.&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;cut&lt;/code&gt; we can remove all the unneeded text in 3 steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;remove the prefix &lt;code&gt;flagIOCmedalist|[[&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;remove the suffix &lt;code&gt;]]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;clean up the names with the “(judo)” disambiguation note. For example from &lt;code&gt;José Rodríguez (judoka)|José Rodríguez&lt;/code&gt; we want to keep only &lt;code&gt;José Rodríguez&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;substring-with-cut&quot;&gt;Substring with &lt;code&gt;cut&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The complete the first step (removing the prefix &lt;code&gt;flagIOCmedalist|[[&lt;/code&gt;) we can use the following command:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;cut&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-c&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;19-&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;... | cut -c&amp;#x22;19-&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The option &lt;code&gt;-c&quot;19-&quot;&lt;/code&gt; means: “take the substring that starts from the character number 19 to the end of the string”. Character 19 is the 20th character considering that strings are &lt;em&gt;“0-indexed”&lt;/em&gt;.
You can use the &lt;code&gt;-c&lt;/code&gt; option to extract any generic substring. For example &lt;code&gt;-c&quot;4-8&quot;&lt;/code&gt; will extract the substring from the 5th to the 9th character. If you leave the range open on the right it will take all the remaining string to the end.&lt;/p&gt;
&lt;p&gt;This filter will be applied to every line and it will modify our stream of data as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Thierry Rey]]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;José Rodríguez (judoka)|José Rodríguez]]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Tibor Kincses (judoka)|Tibor Kincses]]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Aramby Emizh]]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Thierry Rey]]José Rodríguez (judoka)|José Rodríguez]]Tibor Kincses (judoka)|Tibor Kincses]]Aramby Emizh]]...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;splitting-strings-with-cut&quot;&gt;Splitting strings with &lt;code&gt;cut&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Now we would like to remove the suffix &lt;code&gt;]]&lt;/code&gt;.
In order to achieve this goal we can use:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;cut&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-d&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\]&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;... cut -d \] -f 1&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This time we are using the options &lt;code&gt;-d&lt;/code&gt; and &lt;code&gt;-f&lt;/code&gt;.
When we use &lt;code&gt;d&lt;/code&gt; we can specify a character to be used as delimiter (&lt;code&gt;]&lt;/code&gt; in this case), this way &lt;code&gt;cut&lt;/code&gt; will not split the string by character index but in chunks (or columns), generating a new chunk every time the delimiter is encountered along the line.
The option &lt;code&gt;-f&lt;/code&gt; can be combined with &lt;code&gt;-d&lt;/code&gt; to select one or more chunks, in this case we want to select the first chunk.
As we can expect, this will be the status of our data after this command is executed in the pipeline:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Thierry Rey&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;José Rodríguez (judoka)|José Rodríguez&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Tibor Kincses (judoka)|Tibor Kincses&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Aramby Emizh&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Thierry ReyJosé Rodríguez (judoka)|José RodríguezTibor Kincses (judoka)|Tibor KincsesAramby Emizh...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The data looks almost clean, we just need to get rid of the occasional disambiguation notes. These cases can be distinguished by the character &lt;code&gt;|&lt;/code&gt; (pipe) that separates the disambiguation definition from the text that must be rendered by the wikitext engine into HTML code. In these cases we want to keep only the part of the string after the pipe character. Again we can use &lt;code&gt;cut&lt;/code&gt; with the options &lt;code&gt;-d&lt;/code&gt; and &lt;code&gt;-f&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;cut&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-d&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\|&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;... | cut -d \| -f 2&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This time we are using the pipe character as delimiter and we are taking only the second chunk of the string.
This might seem obvious at this stage, but what happens in all the rows where there’s no disambiguation note (and no pipe character)? In this cases we will have just one chunk containing the full line, so what do we get by using the option &lt;code&gt;-f 2&lt;/code&gt;?
Luckily in these cases &lt;code&gt;cut&lt;/code&gt; is smart enough to assume the string is not matching our pattern and returns the entire line, so our data is not destroyed.&lt;/p&gt;
&lt;p&gt;The final result after this command is:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Thierry Rey&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;José Rodríguez&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Tibor Kincses&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Aramby Emizh&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Thierry ReyJosé RodríguezTibor KincsesAramby Emizh...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Our data is finally clean! 🎉&lt;/p&gt;
&lt;h2 id=&quot;counting-and-sorting-with-uniq-and-sort&quot;&gt;Counting and sorting with &lt;code&gt;uniq&lt;/code&gt; and &lt;code&gt;sort&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Now that we have our clean list of names we need to count the occurrences of every athlete and sort.
In order to remove duplicates (and count the occurrences) we can use the command &lt;code&gt;uniq&lt;/code&gt;. This command, when fed with some text, outputs the text itself with adjacent identical lines collapsed to one.
This means that before we can use &lt;code&gt;uniq&lt;/code&gt; we need to have all the names sorted alphabetically so that all the athletes with multiple occurrences have their name repeated on multiple lines one after another.
This can be achieved with the command &lt;code&gt;sort&lt;/code&gt;, which, as you might easily guess, just sorts all the lines received as input in alphabetical order.&lt;/p&gt;
&lt;p&gt;Just to give you a practical example, after using the command &lt;code&gt;sort&lt;/code&gt; our data will look like:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Paweł Nastula&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Peter Seisenbacher&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Peter Seisenbacher&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Priscilla Gneto&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Qin Dongya&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Radomir Kovačević&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Rafael Silva&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Rafael Silva&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Rafaela Silva&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Ramaz Kharshiladze&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;...Paweł NastulaPeter SeisenbacherPeter SeisenbacherPriscilla GnetoQin DongyaRadomir KovačevićRafael SilvaRafael SilvaRafaela SilvaRamaz Kharshiladze...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now we can pipe the &lt;code&gt;uniq -c&lt;/code&gt; command to our data processing flow in order to remove duplicates. The option &lt;code&gt;-c&lt;/code&gt; prints in front of every line the number of consecutive occurrences originally found for that line.
After this command we will have something like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;1 Paweł Nastula&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;2 Peter Seisenbacher&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;1 Priscilla Gneto&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;1 Qin Dongya&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;1 Radomir Kovačević&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;2 Rafael Silva&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;1 Rafaela Silva&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;1 Ramaz Kharshiladze&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;...1 Paweł Nastula2 Peter Seisenbacher1 Priscilla Gneto1 Qin Dongya1 Radomir Kovačević2 Rafael Silva1 Rafaela Silva1 Ramaz Kharshiladze...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note that &lt;a href=&quot;https://en.wikipedia.org/wiki/Rafael_Silva_(judoka)&quot;&gt;Rafael Silva&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Rafaela_Silva&quot;&gt;Rafaela Silva&lt;/a&gt; are two different athletes, it’s not a typo! 😂&lt;/p&gt;
&lt;p&gt;We are almost done. Now we just need to sort our data once again, but this time in reverse order. To do so we can use the &lt;code&gt;sort&lt;/code&gt; command once again, this time as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sort&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-nr&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sort -nr&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Where the option &lt;code&gt;-n&lt;/code&gt; specifies that the first part of every line is a number (so the command can effectively distinguish and sort lines starting for example with &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;10&lt;/code&gt;). The option &lt;code&gt;-r&lt;/code&gt; instead indicates that we want to sort in revers order (bigger first).&lt;/p&gt;
&lt;p&gt;This concludes our pipeline of commands!&lt;/p&gt;
&lt;h2 id=&quot;combining-all-together&quot;&gt;Combining all together&lt;/h2&gt;
&lt;p&gt;Combining all the commands together, our final pipeline will be the following:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-sS&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;https://en.wikipedia.org/wiki/List_of_Olympic_medalists_in_judo?action=raw&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-Eoi&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;flagIOCmedalist\|\[\[(.+)\]\]&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;cut&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-c&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;19-&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;cut&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-d&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\]&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;cut&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-d&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\|&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sort&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;uniq&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sort&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-nr&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;curl -sS &amp;#x22;https://en.wikipedia.org/wiki/List_of_Olympic_medalists_in_judo?action=raw&amp;#x22; |\ grep -Eoi &amp;#x22;flagIOCmedalist\|\[\[(.+)\]\]&amp;#x22; |\ cut -c&amp;#x22;19-&amp;#x22; |\ cut -d \] -f 1 |\ cut -d \| -f 2 |\ sort |\ uniq -c |\ sort -nr&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now that you understood every single part it shouldn’t look very cryptic.&lt;/p&gt;
&lt;p&gt;If we execute it, we can finally discover who are the best Judo Olympic athletes up to Rio 2016:&lt;/p&gt;
&lt;p&gt;… drum rolls …&lt;/p&gt;
&lt;p&gt;With 4 medals:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Driulis_Gonz%C3%A1lez&quot;&gt;Driulis González&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Angelo_Parisi&quot;&gt;Angelo Parisi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With 3 medals:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Teddy_Riner&quot;&gt;Teddy Riner&lt;/a&gt; (The guy in the picture!)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Tadahiro_Nomura&quot;&gt;Tadahiro Nomura&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Ryoko_Tani&quot;&gt;Ryoko Tamura&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Rishod_Sobirov&quot;&gt;Rishod Sobirov&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Mark_Huizinga&quot;&gt;Mark Huizinga&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Idalys_Ortiz&quot;&gt;Idalys Ortiz&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Edith_Bosch&quot;&gt;Edith Bosch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/David_Douillet&quot;&gt;David Douillet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Amarilis_Sav%C3%B3n&quot;&gt;Amarilis Savón&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lot’s of French people there, uh! It’s a shame no Italian athlete is there yet! 😉&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I hope this article showed you that the unix shell is a very powerful tool. If you learn its basic commands and the most common options you will be able to complete a hell of a lot of task directly from the command line by just wisely combining them. You will not need to open an editor and write a long script and then to have an interpreter like &lt;a href=&quot;/tag/node-js&quot;&gt;Node.js&lt;/a&gt; to run it, sometimes the command line is just enough you need!&lt;/p&gt;
&lt;p&gt;If you want to experiment a bit more with this topic, I can propose you a nice variation of this tutorial as exercise:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Can you compute the ranking of the nations with the highest number of medals?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If so, please write your solution in the comments 🤓&lt;/p&gt;
&lt;p&gt;Until next time!&lt;/p&gt;
&lt;p&gt;Cheers&lt;/p&gt;
&lt;h2 id=&quot;alternative-approaches&quot;&gt;Alternative approaches&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;EXTRA&lt;/strong&gt; (Updated on Wed 29th August 2016)&lt;/p&gt;
&lt;p&gt;Some people are suggesting interesting alternative solutions. I think it’s nice to list them here.&lt;/p&gt;
&lt;h3 id=&quot;improved-grep-with-the-reset-match-operator&quot;&gt;Improved &lt;code&gt;grep&lt;/code&gt; with the reset match operator&lt;/h3&gt;
&lt;p&gt;In the newest versions of Gnu grep (not currently available on Mac!) is possible to use the &lt;code&gt;\K&lt;/code&gt; operator (reset match).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;\K&lt;/code&gt; resets the starting point of the reported match. Any previously consumed characters are no longer included in the final match. (See the complete regex on &lt;a href=&quot;https://regex101.com/r/tJ9qI1/1&quot;&gt;regex101&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;With this approach we can rewrite our command as follows, effectively getting rid of all the &lt;code&gt;cut&lt;/code&gt; commands in the pipeline:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-sS&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;https://en.wikipedia.org/wiki/List_of_Olympic_medalists_in_judo?action=raw&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-Po&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;flagIOCmedalist\|\[\[(.* \(judoka\)\|)?\K[^\]]*&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sort&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;uniq&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sort&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-nr&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;curl -sS &amp;#x22;https://en.wikipedia.org/wiki/List_of_Olympic_medalists_in_judo?action=raw&amp;#x22; |\ grep -Po &amp;#x27;flagIOCmedalist\|\[\[(.* \(judoka\)\|)?\K[^\]]*&amp;#x27; |\ sort |\ uniq -c |\ sort -nr&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Solution suggested by &lt;em&gt;pakistanprogrammerclub&lt;/em&gt; in the &lt;a href=&quot;#comment-2844392299&quot;&gt;comments&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;quget&quot;&gt;quget&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/quget&quot;&gt;quget&lt;/a&gt; is a command line utility authored in &lt;a href=&quot;/tag/node-js&quot;&gt;Node.js&lt;/a&gt; that brings together the power of famous node packages such as request, cheerio, and jQuery-like CSS selectors to the command-line.&lt;/p&gt;
&lt;p&gt;To run the following command you need to have Node.js installed and to install &lt;code&gt;quget&lt;/code&gt; with &lt;code&gt;npm i -g quget&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;quget&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;https://en.wikipedia.org/wiki/List_of_Olympic_medalists_in_judo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;#mw-content-text table.wikitable tr:nth-child(n+2) td:nth-child(n+2) a:first-of-type, #mw-content-text table.wikitable tr:nth-child(n+2) td:only-child a:first-of-type&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sort&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;uniq&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sort&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-nr&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;quget https://en.wikipedia.org/wiki/List_of_Olympic_medalists_in_judo &amp;#x22;#mw-content-text table.wikitable tr:nth-child(n+2) td:nth-child(n+2) a:first-of-type, #mw-content-text table.wikitable tr:nth-child(n+2) td:only-child a:first-of-type&amp;#x22; | sort | uniq -c | sort -nr&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Solution by &lt;em&gt;ɹɐqooɟ&lt;/em&gt; in the &lt;a href=&quot;#comment-2840602442&quot;&gt;comments&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;shapeshed&lt;/em&gt; on reddit mentioned &lt;a href=&quot;https://github.com/ericchiang/pup&quot;&gt;pup&lt;/a&gt; an alternative command written in &lt;a href=&quot;/tag/go&quot;&gt;Go&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;awk&quot;&gt;awk&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;awk&lt;/code&gt; is a programming language designed for text processing and typically used as a data extraction and reporting tool. It is a standard feature of most Unix-like operating systems (cit. &lt;a href=&quot;https://en.wikipedia.org/wiki/AWK&quot;&gt;Wikipedia&lt;/a&gt;).&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-sS&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;https://en.wikipedia.org/wiki/List_of_Olympic_medalists_in_judo?action=raw&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;awk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-F&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;\|\\\[\\\[|\\\]&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/flagIOCmedalist/{a[$2]++} END {for (i in a) print a[i], i | &quot;sort -r&quot;}&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;curl -sS &amp;#x22;https://en.wikipedia.org/wiki/List_of_Olympic_medalists_in_judo?action=raw&amp;#x22; | awk -F&amp;#x27;\|\\\[\\\[|\\\]&amp;#x27; &amp;#x27;/flagIOCmedalist/{a[$2]++} END {for (i in a) print a[i], i | &amp;#x22;sort -r&amp;#x22;}&amp;#x27;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This didn’t work for me on a Mac, but it did work on an Ubuntu machine.&lt;/p&gt;
&lt;p&gt;Solution by &lt;em&gt;Boris P.&lt;/em&gt; on Facebook.&lt;/p&gt;
&lt;h3 id=&quot;sed&quot;&gt;sed&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;sed&lt;/code&gt; (stream editor) is a Unix utility that parses and transforms text, using a simple, compact programming language. (See more on &lt;a href=&quot;https://en.wikipedia.org/wiki/Sed&quot;&gt;Wikipedia&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;We can use &lt;code&gt;sed&lt;/code&gt; as an alternative to grep to extract the names of the judokas in one shot. Our final command will look like:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-sS&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;https://en.wikipedia.org/wiki/List_of_Olympic_medalists_in_judo?action=raw&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sed&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-n&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/flagIOCmedalist/{s/^.*\[\[//; s/\]\].*//; s/^.*|//;p}&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sort&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;uniq&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sort&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-nr&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;curl -sS &amp;#x22;https://en.wikipedia.org/wiki/List_of_Olympic_medalists_in_judo?action=raw&amp;#x22; | sed -n &amp;#x27;/flagIOCmedalist/{s/^.*\[\[//; s/\]\].*//; s/^.*|//;p}&amp;#x27; | sort | uniq -c | sort -nr&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This approach doesn’t seem to be working on Mac tough.&lt;/p&gt;
&lt;p&gt;Solution suggested by &lt;em&gt;pakistanprogrammerclub&lt;/em&gt; in the &lt;a href=&quot;#comment-2844392299&quot;&gt;comments&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;in-browser-developer-console&quot;&gt;In-Browser developer console&lt;/h3&gt;
&lt;p&gt;You can extract data from the current web page using the developer console that most browsers offer (Chrome, Opera, Firefox…). After opening &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_Olympic_medalists_in_judo&quot;&gt;our Wikipedia page of interest&lt;/a&gt;, in the developer console you can run the following &lt;a href=&quot;/tag/javascript&quot;&gt;JavaScript&lt;/a&gt; one-liner:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;[].&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;slice&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;table tr td:nth-child(n+2) &gt; a:nth-child(1), table tr:nth-child(3) td &gt; a:nth-child(1)&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;innerText&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;reduce&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;res&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;el&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;res&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;el&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;res&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;el&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;] &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;res&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;el&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;] &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;res&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}, {})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;;[].slice  .call(    document.querySelectorAll(      &amp;#x27;table tr td:nth-child(n+2) &gt; a:nth-child(1), table tr:nth-child(3) td &gt; a:nth-child(1)&amp;#x27;,    ),  )  .map(function (e) {    return e.innerText  })  .reduce(function (res, el) {    res[el] = res[el] ? res[el] + 1 : 1    return res  }, {})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The result is an object with the medalists as keys, and the count as values. JavaScript objects are unordered so sorting is left as an exercise for the reader.&lt;/p&gt;
&lt;p&gt;Solution by &lt;em&gt;lacksconfidence&lt;/em&gt; on &lt;a href=&quot;https://news.ycombinator.com/item?id=12293209&quot;&gt;HackerNews&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;xpath-and-google-spreadsheet-or-python&quot;&gt;XPath and Google Spreadsheet or Python&lt;/h3&gt;
&lt;p&gt;XPath (XML Path Language) is a query language for selecting nodes from an XML document (cit. &lt;a href=&quot;https://en.wikipedia.org/wiki/XPath&quot;&gt;Wikipedia&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;By downloading the HTML of the Wikipedia page and applying an XPath selector like &lt;code&gt;//table//tr/td[2]/a[1]/text()&lt;/code&gt; we should be able to extract all the gold medalist in the tables. In the same fashion we can build a slightly more complex solution by combining more selectors:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;//table//tr/td[2]/a[1]/text()|//table//tr/td[3]/a[1]/text()|//table//tr/td[4]/a[1]/text()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;//table//tr/td[2]/a[1]/text()|//table//tr/td[3]/a[1]/text()|//table//tr/td[4]/a[1]/text()&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;With this approach we can easily import data into a spreadsheet software like Google Spreadsheet. In Google Spreadsheet we can use the function &lt;code&gt;IMPORTXML&lt;/code&gt; to run an XPath expression against an XML or HTML document available on a given URL.&lt;/p&gt;
&lt;p&gt;I created an &lt;a href=&quot;https://docs.google.com/spreadsheets/d/1VVFIGFcmuVpDRBR9xKe-s_T4tJk0-tLcvuf_gKVuKfA/edit?usp=sharing&quot;&gt;example document&lt;/a&gt; that you can check out if you are curious to see this feature in action.&lt;/p&gt;
&lt;p&gt;Solution based on comments by &lt;em&gt;turtlebits&lt;/em&gt; and &lt;em&gt;san_dimitri&lt;/em&gt; on &lt;a href=&quot;https://news.ycombinator.com/item?id=12294667&quot;&gt;HackerNews&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’m glad to know I inspired &lt;a href=&quot;https://twitter.com/@NikolaiHampton&quot;&gt;Nikolai Hampton&lt;/a&gt; to write an &lt;a href=&quot;http://3583bytesready.net/2016/08/17/scraping-data-python-xpath/&quot;&gt;amazing article&lt;/a&gt; that illustrates how to solve this problem using XPath expressions in &lt;strong&gt;Python&lt;/strong&gt;. If you like Python the article is absolutely a must, don’t miss it out!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/extracting-data-from-wikipedia-using-curl-grep-cut-and-other-bash-commands.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/extracting-data-from-wikipedia-using-curl-grep-cut-and-other-bash-commands.png" width="1200" height="630"/></media:content><category>bash</category><category>shell</category><author>Luciano Mammino</author><comments>https://loige.co/extracting-data-from-wikipedia-using-curl-grep-cut-and-other-bash-commands/#comments</comments><enclosure url="https://loige.co/og/extracting-data-from-wikipedia-using-curl-grep-cut-and-other-bash-commands.png" length="0" type="image/png"/></item><item><title>React on the Server for Beginners: Build a Universal React and Node App</title><link>https://loige.co/react-on-the-server-for-beginners-build-a-universal-react-and-node-app/</link><guid isPermaLink="true">https://loige.co/react-on-the-server-for-beginners-build-a-universal-react-and-node-app/</guid><description>This article explains how to build a simple Universal JavaScript application using React, React Router and Express. It shows how to implement server side rendering with React and Node.js to create an isomorphic app.</description><pubDate>Mon, 29 Aug 2016 21:49:47 GMT</pubDate><content:encoded>&lt;p&gt;I recently wrote a new article in collaboration with one of my favourite web development websites: the amazing &lt;a href=&quot;https://scotch.io/&quot;&gt;Scotch.io&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The article talk about using &lt;a href=&quot;/tag/react&quot;&gt;React&lt;/a&gt; both on client and on the server (with &lt;a href=&quot;/tag/node-js&quot;&gt;Node.js&lt;/a&gt;) in an attempt to build a simple “Universal JavaScript” (a.k.a “Isomorphic”) application.&lt;/p&gt;
&lt;p&gt;The application is called “Judo Heroes” (&lt;a href=&quot;http://loige.co/extracting-data-from-wikipedia-using-curl-grep-cut-and-other-bash-commands/&quot;&gt;did you even noticed recently that I’m kind of fond of Judo?&lt;/a&gt;) and it showcases some of the best Judo athletes for their number of medals won during the Olympic Games and in other important international tournaments.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://judo-heroes.herokuapp.com/&quot;&gt;&lt;img alt=&quot;Judo Heroes main page screenshot&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;600&quot; height=&quot;608&quot; src=&quot;https://loige.co/_astro/universal-javascript-judo-heroes-athlete-selection-1.DEzZeieG_2rsQNE.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you are curious you can &lt;a href=&quot;https://judo-heroes.herokuapp.com/&quot;&gt;check out the live demo&lt;/a&gt; or &lt;a href=&quot;https://github.com/lmammino/judo-heroes&quot;&gt;have a look at the source code on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Then, if you want to follow the tutorial, you should definitely read the article on scotch:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://scotch.io/tutorials/react-on-the-server-for-beginners-build-a-universal-react-and-node-app&quot;&gt;React on the Server for Beginners: Build a Universal React and Node App&lt;/a&gt;
&lt;a href=&quot;https://scotch.io/tutorials/react-on-the-server-for-beginners-build-a-universal-react-and-node-app&quot;&gt;&lt;img alt=&quot;React on the Server for Beginners: Build a Universal React and Node App Article Banner&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1090&quot; height=&quot;544&quot; src=&quot;https://loige.co/_astro/scotch-featured-image-react-on-the-server.BEZJNjpE_Z1LwMKM.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this article we are going to learn how to build a simple “Universal JavaScript” application (a.k.a. “Isomorphic”) using &lt;strong&gt;React&lt;/strong&gt;, &lt;strong&gt;React Router&lt;/strong&gt; and &lt;strong&gt;Express&lt;/strong&gt;. We will also use some &lt;strong&gt;Webpack&lt;/strong&gt; and &lt;strong&gt;Babel&lt;/strong&gt; to leverage the latest &lt;strong&gt;ES2015&lt;/strong&gt; Syntax.&lt;/p&gt;
&lt;p&gt;Enjoy it and feel free to leave your comments here or on the original article.&lt;/p&gt;
&lt;p&gt;Cheers!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/react-on-the-server-for-beginners-build-a-universal-react-and-node-app.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/react-on-the-server-for-beginners-build-a-universal-react-and-node-app.png" width="1200" height="630"/></media:content><category>node-js</category><category>react</category><category>collaboration</category><author>Luciano Mammino</author><comments>https://loige.co/react-on-the-server-for-beginners-build-a-universal-react-and-node-app/#comments</comments><enclosure url="https://loige.co/og/react-on-the-server-for-beginners-build-a-universal-react-and-node-app.png" length="0" type="image/png"/></item><item><title>To promise or to callback? That is the question...</title><link>https://loige.co/to-promise-or-to-callback-that-is-the-question/</link><guid isPermaLink="true">https://loige.co/to-promise-or-to-callback-that-is-the-question/</guid><description>We explore two approaches to support both callbacks and promises in async JavaScript modules: 1) promisify callback functions, 2) make callback optional and return promise. The second allows flexible use of callbacks or promises.</description><pubDate>Sun, 14 Feb 2016 13:32:00 GMT</pubDate><content:encoded>&lt;p&gt;You are building the next cool &lt;a href=&quot;/tag/javascript&quot;&gt;JavaScript&lt;/a&gt; or &lt;a href=&quot;/tag/node-js&quot;&gt;Node.js&lt;/a&gt; module with a lot of asynchronous functions and you are very happy about it. At some point a terrible doubt assaults you:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Should my API offer support for callbacks or should it be promise based?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this article we are going to show a very simple way to add support for both promises and callbacks in our asynchronous modules, this way we can make everyone happy and our libraries much more flexible.&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The problem&lt;/h2&gt;
&lt;p&gt;Promises can be used as a nice replacement for callbacks, that’s a well know fact in the JavaScript world today. Promises turn out to be very useful in making our code more readable and easy to reason about.
But while promises bring many advantages, they also require the developer to understand many non-trivial concepts in order to use them correctly and proficiently. For this and other reasons, in some cases it might be more practical to prefer callbacks over promises.&lt;/p&gt;
&lt;p&gt;Now let’s imagine for a moment that we want to build a public library that performs asynchronous operations. What do we do? Do we create a &lt;em&gt;callback oriented&lt;/em&gt; API or a &lt;em&gt;promise oriented&lt;/em&gt; one? Do we need to be opinionated on one side or another or there are ways to support both and make everyone happy?&lt;/p&gt;
&lt;p&gt;There are at least 2 approaches to face this question, let’s see how they work!&lt;/p&gt;
&lt;p&gt;##1. The “I don’t fu**in’ care” approach&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://i.giphy.com/on45FojvYvnsQ.gif&quot; alt=&quot;I don&amp;#x27;t care gif animation Judy Garland&quot;&gt;&lt;/p&gt;
&lt;p&gt;The first approach, used for instance by libraries like &lt;a href=&quot;https://www.npmjs.com/package/request&quot;&gt;request&lt;/a&gt;, &lt;a href=&quot;https://www.npmjs.com/package/redis&quot;&gt;redis&lt;/a&gt; and &lt;a href=&quot;https://www.npmjs.com/package/mysql&quot;&gt;mysql&lt;/a&gt; as well as all the node native async functions, consists in offering a simple API based only on callbacks and leave the developer the option to &lt;em&gt;promisify&lt;/em&gt; the exposed functions if needed.
Some of these libraries are a bit more elaborated and they provide helpers to be able to &lt;em&gt;promisify&lt;/em&gt; all the asynchronous functions they offer at once, but the developer still needs to someway “convert” the exposed API to be able to use promises.
That’s why I believe this approach feels a bit rude like:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Do you want to use Promise? I don’t care, it’s your problem… just promisify what you want and leave me alone!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are a number of modules out there that can help to promisify a callback based function. The first two that come in my mind are &lt;a href=&quot;http://bluebirdjs.com/&quot;&gt;Bluebird&lt;/a&gt; with its &lt;a href=&quot;http://bluebirdjs.com/docs/api/promise.promisify.html&quot;&gt;&lt;code&gt;Promise.promisify()&lt;/code&gt;&lt;/a&gt; method and &lt;a href=&quot;https://www.npmjs.com/package/es6-promisify&quot;&gt;es6-promisify&lt;/a&gt; which adopts ES2015 promises.&lt;/p&gt;
&lt;p&gt;Let’s see a quick example of this approach with &lt;strong&gt;es6-promisify&lt;/strong&gt;. In the following snippet of code we are going to promisify the native &lt;code&gt;fs.readFile()&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;use strict&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;fs&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;fs&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;promisify&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;es6-promisify&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;readFile&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;promisify&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;fs&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;readFile&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;readFile&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;last_action_hero.txt&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;utf-8&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&amp;#x27;use strict&amp;#x27;const fs = require(&amp;#x27;fs&amp;#x27;)const promisify = require(&amp;#x27;es6-promisify&amp;#x27;)let readFile = promisify(fs.readFile)readFile(&amp;#x27;last_action_hero.txt&amp;#x27;, &amp;#x27;utf-8&amp;#x27;)  .then(content =&gt; console.log(content))  .catch(err =&gt; console.error(err))&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The example is very straightforward, we just have to call &lt;code&gt;promisify(fs.readFile)&lt;/code&gt; to obtain a promisified version of the &lt;code&gt;readFile&lt;/code&gt; function. As we might expect we can invoke this function without passing the &lt;code&gt;callback&lt;/code&gt; argument and we get a &lt;code&gt;Promise&lt;/code&gt; object as output, so we can immediately use it and call the handy &lt;code&gt;then&lt;/code&gt; and &lt;code&gt;catch&lt;/code&gt; methods.&lt;/p&gt;
&lt;p&gt;Unfortunately the new &lt;code&gt;Promise&lt;/code&gt; implementation of ES2015 does not offer a built-in &lt;em&gt;promisify&lt;/em&gt; mechanism (yet…).&lt;/p&gt;
&lt;h2 id=&quot;2-the-no-strong-feelings-way&quot;&gt;2. The “No strong feelings” way&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;http://i.giphy.com/7U7oEJkAiP5Xq.gif&quot; alt=&quot;I have no strong feeling either way futurama gif animation&quot;&gt;&lt;/p&gt;
&lt;p&gt;This approach is more transparent and I would say more… “polite”!
It is also based on the concept of offering a simple callback oriented API, but &lt;strong&gt;it makes the callback argument optional&lt;/strong&gt;.
Whenever the callback is passed as an argument the function will behave normally executing the callback on completion or on failure. Instead &lt;strong&gt;when the callback is not passed to the function, it will immediately return a Promise object&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This approach effectively combines callbacks and promises in a way that allows the developer to choose at call time what interface to adopt, without any need to promisify the function in advance. Many libraries like &lt;a href=&quot;https://www.npmjs.com/package/mongoose&quot;&gt;mongoose&lt;/a&gt; and &lt;a href=&quot;https://www.npmjs.com/package/sequelize&quot;&gt;sequelize&lt;/a&gt; are supporting this approach.&lt;/p&gt;
&lt;p&gt;Let’s see a simple implementation of this approach with an example. Let’s assume we want to implement a dummy module that executes divisions asynchronously:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#AF4238&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#AF4238&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;asyncDivision&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;divisor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;cb&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;reject&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// [1]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;nextTick&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#016C9A&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!==&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;||&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#016C9A&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;divisor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!==&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;||&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;divisor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Invalid operands&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;cb&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;cb&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// [2]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;reject&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;divisor&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;cb&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;cb&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// [3]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;module.exports = function asyncDivision(dividend, divisor, cb) {  return new Promise((resolve, reject) =&gt; {    // [1]    process.nextTick(() =&gt; {      if (        typeof dividend !== &amp;#x27;number&amp;#x27; ||        typeof divisor !== &amp;#x27;number&amp;#x27; ||        divisor === 0      ) {        let error = new Error(&amp;#x27;Invalid operands&amp;#x27;)        if (cb) {          return cb(error)        } // [2]        return reject(error)      }      var result = dividend / divisor      if (cb) {        return cb(null, result)      } // [3]      return resolve(result)    })  })}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The code of the module is very simple, but there are some details (marked with a number in square brackets) that are worth to be underlined:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;First, we return a new promise created using the ES2015 &lt;code&gt;Promise&lt;/code&gt; constructor. We define the whole logic inside the function passed as argument to the constructor.&lt;/li&gt;
&lt;li&gt;In case of error, we reject the promise, but if the callback was passed at call time we also execute the callback to propagate the error.&lt;/li&gt;
&lt;li&gt;After we calculate the result we resolve the promise, but again, if there’s a callback, we propagate the result to the callback as well.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now to complete the example, let’s see now how we can use this module with both callbacks and promises:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// callback oriented usage&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;asyncDivision&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// promise oriented usage&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;asyncDivision&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;22&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;11&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// callback oriented usageasyncDivision(10, 2, (error, result) =&gt; {  if (error) {    return console.error(error)  }  console.log(result)})// promise oriented usageasyncDivision(22, 11)  .then(result =&gt; console.log(result))  .catch(error =&gt; console.error(error))&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;It should be clear that with very little effort, the developers who are going to use our new module will be able to easily choose the style that best suits their needs without having to introduce an external “promisification” function whenever they want to leverage promises.&lt;/p&gt;
&lt;h3 id=&quot;a-little-caveat-and-an-alternative-implementation&quot;&gt;A little caveat and an alternative implementation&lt;/h3&gt;
&lt;p&gt;As &lt;a href=&quot;https://disqus.com/by/amar_zavery&quot;&gt;Amar Zavery&lt;/a&gt; pointed out in a &lt;a href=&quot;//loige.co/to-promise-or-to-callback-that-is-the-question/#comment-3184972856&quot;&gt;comment here&lt;/a&gt;, this approach is not perfect.&lt;/p&gt;
&lt;p&gt;If we use the function with the callback approach, we still have created and returned a promise that behaves in an inconsistent way (never &lt;em&gt;resolved&lt;/em&gt;, nor &lt;em&gt;rejected&lt;/em&gt;). Let’s make this clear with an example:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;asyncDivision&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`Promise resolved`&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`Promise rejected`&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;asyncDivision(2, 0, console.log)  .then(() =&gt; console.log(&amp;#x60;Promise resolved&amp;#x60;))  .catch(() =&gt; console.error(&amp;#x60;Promise rejected&amp;#x60;))&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In this example, we are passing a callback (&lt;code&gt;console.log&lt;/code&gt;) to our function but also using the returned promise to print some extra information.
With our implementation of &lt;code&gt;asyncDivision&lt;/code&gt; either the &lt;code&gt;then&lt;/code&gt; block and the &lt;code&gt;catch&lt;/code&gt; block are never executed because the function is interrupted as soon as the callback is used.&lt;/p&gt;
&lt;p&gt;This is most of the time negligible because is very unlikely that somebody will be using the function with this mixed async approach (we could even argue that doing so would be a bad practice).&lt;/p&gt;
&lt;p&gt;Anyway, we can get rid of this issue by re-implementing our async function as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#AF4238&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#AF4238&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;asyncDivision&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;divisor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;cb&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// internal implementation, callback based&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;_asyncDivision&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;divisor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;cb&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;nextTick&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#016C9A&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!==&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;||&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#016C9A&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;divisor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!==&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;||&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;divisor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;cb&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Invalid operands&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;cb&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;divisor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;cb&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;_asyncDivision&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;divisor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;cb&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// optional promisification, only if no callback&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;reject&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;_asyncDivision&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;divisor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;reject&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;module.exports = function asyncDivision(dividend, divisor, cb) {  // internal implementation, callback based  function _asyncDivision(dividend, divisor, cb) {    process.nextTick(() =&gt; {      if (        typeof dividend !== &amp;#x27;number&amp;#x27; ||        typeof divisor !== &amp;#x27;number&amp;#x27; ||        divisor === 0      ) {        return cb(new Error(&amp;#x27;Invalid operands&amp;#x27;))      }      return cb(null, dividend / divisor)    })  }  if (cb) {    return _asyncDivision(dividend, divisor, cb)  }  // optional promisification, only if no callback  return new Promise((resolve, reject) =&gt;    _asyncDivision(      dividend,      divisor,      (err, result) =&gt; (err ? reject(err) : resolve(result))    )  )}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This code generates a promise only if no callback is used. So if we provide a callback as the last argument, and then we try to use &lt;code&gt;catch&lt;/code&gt; or &lt;code&gt;then&lt;/code&gt; on the returning value, we will get an explicit runtime error:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TypeError: Cannot read property &apos;then&apos; of undefined&lt;/code&gt; or&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TypeError: Cannot read property &apos;catch&apos; of undefined&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While this approach is probably more correct, it is also more verbose and, if it becomes a recurrent practice in your development process, you are better off using some promisification library.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;As usual I hope this article has been useful and that it will ignite some interesting conversation.&lt;/p&gt;
&lt;p&gt;I think from the tone of the article it’s quite clear that I prefer to opt for the “polite” approach, but I am very curious to know what are your opinions about this topic and if you are an “I don’t care” or a “whatever” person when you create your asynchronous functions in your modules.&lt;/p&gt;
&lt;p&gt;Let me know your thoughts in the comments.&lt;/p&gt;
&lt;p&gt;Until next time! :)&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/to-promise-or-to-callback-that-is-the-question.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/to-promise-or-to-callback-that-is-the-question.png" width="1200" height="630"/></media:content><category>javascript</category><category>node-js</category><author>Luciano Mammino</author><comments>https://loige.co/to-promise-or-to-callback-that-is-the-question/#comments</comments><enclosure url="https://loige.co/og/to-promise-or-to-callback-that-is-the-question.png" length="0" type="image/png"/></item><item><title>Announcing the book &quot;Node.js design patterns - second edition&quot;</title><link>https://loige.co/announcing-the-book-node-js-design-patterns-second-edition/</link><guid isPermaLink="true">https://loige.co/announcing-the-book-node-js-design-patterns-second-edition/</guid><description>The author announces the release of &quot;Node.js design patterns - second edition&quot;, a new book covering design patterns for Node.js and JavaScript. It includes updated code for Node v6 and ES2015 across 11 chapters and 100+ examples.</description><pubDate>Sun, 31 Jul 2016 18:25:00 GMT</pubDate><content:encoded>&lt;p&gt;In this post I am going to introduce my last side-project: “Node.js design
patterns — second edition”, a technical book about Node.js and design patterns
published by Packt.&lt;/p&gt;
&lt;p&gt;This blog has been a very quite place in the last 8-9 months, this is because
almost all my free time has been absorbed by one of my most ambitious side
projects: co-writing a book about &lt;a href=&quot;/tag/node-js&quot;&gt;Node.js&lt;/a&gt; and
&lt;a href=&quot;/tag/design-patterns&quot;&gt;design patterns&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;I am finally happy to announce that “Node.js design patterns — second edition”
has been published.&lt;/p&gt;
&lt;p&gt;You can keep reading this post to find out more or have a look at the
&lt;a href=&quot;https://www.nodejsdesignpatterns.com&quot;&gt;official website&lt;/a&gt;. If all of this is
convincing enough you can even decide to buy the paperback or the e-book on
&lt;a href=&quot;https://www.packtpub.com/web-development/nodejs-design-patterns-second-edition&quot;&gt;Packt&lt;/a&gt;,
&lt;a href=&quot;http://amzn.to/2a418Q2&quot;&gt;Amazon&lt;/a&gt; or
&lt;a href=&quot;http://shop.oreilly.com/product/9781785885587.do&quot;&gt;O’Reilly&lt;/a&gt; :P&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nodejsdesignpatterns.com&quot;&gt;&lt;img alt=&quot;Node.js design patterns second edition book cover&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;800&quot; height=&quot;987&quot; src=&quot;https://loige.co/_astro/book-cover-nodejs-design-patterns-second-edition-mario-casciaro-luciano-mammino.DkNDr07D_Z1Dt4IY.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-making-of&quot;&gt;The making of&lt;/h2&gt;
&lt;p&gt;As you might have noticed, this book is the second edition of an
&lt;a href=&quot;http://amzn.to/2a9FgDP&quot;&gt;existing book on the topic&lt;/a&gt; — I dare to say &lt;em&gt;one of the
best&lt;/em&gt; books on the topic — that &lt;a href=&quot;http://www.mariocasciaro.me&quot;&gt;Mario Casciaro&lt;/a&gt;
put together a couple of years ago.&lt;/p&gt;
&lt;p&gt;I was contacted by Mario in November last year because he was looking for
somebody willing to help him in creating a new edition of the book. I don’t know
yet why he thought I might have been the right person (and I am still flattered
about this) but, being his book one of my favourites, I almost immediately
decided to accept the challenge and work with him and Packt on this new edition.&lt;/p&gt;
&lt;p&gt;It took almost 9 months from the first idea to having the printed book on my
desk. I have to admit it was an incredibly interesting experience for me. I
learned a lot and I definitely feel I strengthened my knowledge of Node.js and
design patterns, I worked with super skilled technical reviewers like
&lt;a href=&quot;http://joelpurra.com&quot;&gt;Joel Purra&lt;/a&gt; and
&lt;a href=&quot;https://twitter.com/tanepiper&quot;&gt;Tane Piper&lt;/a&gt; and with the amazing team at Packt.
I also had chance to experiment with some new cool technologies like
&lt;a href=&quot;/tag/react&quot;&gt;React&lt;/a&gt; and new ways of building websites like &lt;strong&gt;Universal
JavaScript&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;content-of-the-book&quot;&gt;Content of the book&lt;/h2&gt;
&lt;p&gt;The book has been heavily updated: more than the 50% of the original content
from the first edition was changed. These changes were mostly about updating all
the code examples to &lt;strong&gt;Node v6&lt;/strong&gt; and &lt;strong&gt;EcmaScript 2015&lt;/strong&gt;, upgrading all the
obsolete content, introducing some new interesting examples and design patterns
and a new entire chapter dedicated to &lt;strong&gt;Universal Javascript&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The final result counts &lt;strong&gt;11 chapters&lt;/strong&gt;, more than &lt;strong&gt;500 pages&lt;/strong&gt; and more than
&lt;strong&gt;100 code examples&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The first two chapters provide basic informations about the Node.js platform and
the new features introduced with EcmaScript 2015.&lt;/p&gt;
&lt;p&gt;Chapter 3 and 4 go deep into the topic of asynchronous programming exploring
different approaches (callbacks, promises, events, async/await) and design
patterns to exploit all the most common scenarios.&lt;/p&gt;
&lt;p&gt;Chapter 5 discusses one of the most important patterns in Node.js: streams. It
shows you how to process data with transform streams and how to combine them
into different layouts.&lt;/p&gt;
&lt;p&gt;Chapter 6 is probably the core of this book diving deep into the most popular
conventional design patterns and showing how unconventional they might look in
Node.js. It also introduces the reader to some emerging design patterns that are
used only with JavaScript and Node.js.&lt;/p&gt;
&lt;p&gt;Chapter 7 analyses the different solutions for linking the modules of an
application together investigating design patterns such as Dependency Injection
and the service locator pattern.&lt;/p&gt;
&lt;p&gt;Chapter 8 is an entire new chapter that explores one of the most interesting
capabilities of modern JavaScript web applications: being able to share
application code between the frontend and the backend. Across this chapter we
learn the basic principles of Universal (a.k.a. Isomorphic) JavaScript by
building a simple web application with React, Webpack, and Babel.&lt;/p&gt;
&lt;p&gt;Chapters 9, 10 and 11 go into more advanced and enterprise topics like “Advanced
Asynchronous Recipes”, “Scalability and Architectural Patterns” and finally
“Messaging and Integration Patterns”.&lt;/p&gt;
&lt;p&gt;You can read
&lt;a href=&quot;https://www.nodejsdesignpatterns.com/files/nodejs_design_patterns_preview_chapter1.pdf&quot;&gt;a sample of the book&lt;/a&gt;
containing the full table of contents and the first chapter for FREE on the
&lt;a href=&quot;https://www.nodejsdesignpatterns.com&quot;&gt;official website&lt;/a&gt;, don’t miss it!&lt;/p&gt;
&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;Apart from Mario, Joel and Tane, which I already mentioned previously, I have to
spend a special word of thank you for my dear friends
&lt;a href=&quot;https://twitter.com/dhigit9&quot;&gt;Anton Whalley&lt;/a&gt;,
&lt;a href=&quot;https://twitter.com/cirpo&quot;&gt;Alessandro Cinelli&lt;/a&gt;,
&lt;a href=&quot;https://twitter.com/bit_shark&quot;&gt;Andrea Giuliano&lt;/a&gt; and
&lt;a href=&quot;https://twitter.com/andreaman87&quot;&gt;Andrea Mangano&lt;/a&gt;. They are amazing guys and
they have been precious supporters during the creation of this new book with
words of encouragement and incredibly meaningful technical advices.&lt;/p&gt;
&lt;p&gt;Thank you once again guys :)&lt;/p&gt;
&lt;h2 id=&quot;whats-next&quot;&gt;What’s next&lt;/h2&gt;
&lt;p&gt;Well, I don’t plan to start writing a new book anytime soon in case you are
wondering… :D But I surely will keep improving my knowledge and experience
with Node.js and maybe I will also start to explore some new field in the
amazing world of programming. I guess I will also be able to keep posting
articles here more often :)&lt;/p&gt;
&lt;p&gt;So stay tuned for the next post :)&lt;/p&gt;
&lt;p&gt;I will go now to take a pint to celebrate the release… Cheers 🍻&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/announcing-the-book-node-js-design-patterns-second-edition.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/announcing-the-book-node-js-design-patterns-second-edition.png" width="1200" height="630"/></media:content><category>node-js</category><category>books</category><category>design-patterns</category><author>Luciano Mammino</author><comments>https://loige.co/announcing-the-book-node-js-design-patterns-second-edition/#comments</comments><enclosure url="https://loige.co/og/announcing-the-book-node-js-design-patterns-second-edition.png" length="0" type="image/png"/></item><item><title>Two Interviews about Node.js, JavaScript and being a book author</title><link>https://loige.co/two-interviews-about-node-js-javascript-and-being-a-book-author/</link><guid isPermaLink="true">https://loige.co/two-interviews-about-node-js-javascript-and-being-a-book-author/</guid><description>Luciano Mammino recently participated in two interviews discussing his work with Node.js and JavaScript as well as his experience as an author writing books about Node.js design patterns.</description><pubDate>Sun, 25 Sep 2016 13:24:08 GMT</pubDate><content:encoded>&lt;p&gt;In the last month I had the pleasure to seeing published two interviews regarding my life as developer with &lt;a href=&quot;/tag/node-js&quot;&gt;Node.js&lt;/a&gt; and &lt;a href=&quot;/tag/javascript&quot;&gt;JavaScript&lt;/a&gt; and about being a book author with &lt;a href=&quot;https://www.nodejsdesignpatterns.com&quot;&gt;Node.Js design patterns second edition&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The first interview was made with the &lt;strong&gt;Packt Publishing team&lt;/strong&gt; and it was published in their own website:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://www.packtpub.com/books/content/nodejs-its-easy-get-things-done&quot;&gt;With Node.js, it’s easy to get things done&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.packtpub.com/books/content/nodejs-its-easy-get-things-done&quot;&gt;&lt;img alt=&quot;With Node.js, it’s easy to get things done interview image&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;700&quot; height=&quot;350&quot; src=&quot;https://loige.co/_astro/nodejs-its-easy-get-things-done-packt-interview-luciano-mammino.MgfEgbfM_Z12N8iI.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The second interview was made by &lt;a href=&quot;https://twitter.com/tompeham&quot;&gt;Thomas Peham&lt;/a&gt;, marketing manager at &lt;a href=&quot;http://usersnap.com/blog/&quot;&gt;UserSnap&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://usersnap.com/blog/developer-community-luciano-mammino/&quot;&gt;Meet the community: Luciano Mammino, software developer from Sicily&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://usersnap.com/blog/developer-community-luciano-mammino/&quot;&gt;&lt;img alt=&quot;Meet the community: Luciano Mammino, software developer from Sicily interview image&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;700&quot; height=&quot;350&quot; src=&quot;https://loige.co/_astro/developer-community-luciano-mammino-usersnap-interview.HRDvPLWf_ZjVFgo.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I think both interviews turned out to be pretty cool, especially because I had a chance to express my vision about the future of JavaScript and Node.js, technologies on which I am investing most of my time.&lt;/p&gt;
&lt;p&gt;Feel more than welcome to let me know if you share my vision or not here in the comments.&lt;/p&gt;
&lt;p&gt;Until next time!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/two-interviews-about-node-js-javascript-and-being-a-book-author.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/two-interviews-about-node-js-javascript-and-being-a-book-author.png" width="1200" height="630"/></media:content><category>collaboration</category><category>node-js</category><category>javascript</category><author>Luciano Mammino</author><comments>https://loige.co/two-interviews-about-node-js-javascript-and-being-a-book-author/#comments</comments><enclosure url="https://loige.co/og/two-interviews-about-node-js-javascript-and-being-a-book-author.png" length="0" type="image/png"/></item><item><title>How to crack a JWT token: two articles about distributed computing, ZeroMQ &amp; Node.js</title><link>https://loige.co/how-to-crack-a-jwt-token-two-articles-about-distributed-computing-zeromq-node-js/</link><guid isPermaLink="true">https://loige.co/how-to-crack-a-jwt-token-two-articles-about-distributed-computing-zeromq-node-js/</guid><description>This blog post explains how to build a distributed application using Node.js and ZeroMQ that cracks JWT tokens. It provides a step-by-step guide on implementing the application and links to two in-depth articles on RisingStack that cover the theory and coding details.</description><pubDate>Mon, 24 Oct 2016 22:44:51 GMT</pubDate><content:encoded>&lt;p&gt;In the last 2 weeks I add the pleasure to release an article (in two parts) in collaboration with &lt;a href=&quot;http://risingstack.com/&quot;&gt;RisingStack&lt;/a&gt;, one of the most famous companies in the &lt;a href=&quot;/tag/node-js&quot;&gt;Node.js&lt;/a&gt; ecosystem.&lt;/p&gt;
&lt;p&gt;The article explains how to build a distributed application using Node.js and &lt;a href=&quot;/tag/zeromq&quot;&gt;ZeroMQ&lt;/a&gt; and provides an example that I believe it’s very actual and interesting: a &lt;a href=&quot;/tag/jwt&quot;&gt;JWT&lt;/a&gt; token cracker.&lt;/p&gt;
&lt;p&gt;If you are into Node.js, ZeroMQ, security or distributed application you can read the two articles in the community section of RisingStack.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://community.risingstack.com/zeromq-node-js-cracking-jwt-tokens-1/&quot;&gt;&lt;img alt=&quot;ZeroMQ &amp;amp;#x26; Node.js Tutorial - Cracking JWT Tokens&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;525&quot; src=&quot;https://loige.co/_astro/zeromq-nodejs-tutorial-cracking-jwt-tokens.D5DEP0OK_ZJUNGg.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://community.risingstack.com/zeromq-node-js-cracking-jwt-tokens-1/&quot;&gt;ZeroMQ &amp;#x26; Node.js Tutorial - Cracking JWT Tokens (Part 1.)&lt;/a&gt;&lt;/strong&gt;, is focused mostly on theory and describes what a JWT token is and what will be our approach to try to crack one of them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://community.risingstack.com/zeromq-node-js-cracking-jwt-tokens-part2/&quot;&gt;ZeroMQ &amp;#x26; Node.js Tutorial - Cracking JWT Tokens (Part 2.)&lt;/a&gt;&lt;/strong&gt;, instead, focuses on coding and it’s a step by step guide on how to build the working application.&lt;/p&gt;
&lt;p&gt;The application is also freely available on &lt;a href=&quot;https://www.npmjs.com/package/distributed-jwt-cracker&quot;&gt;NPM&lt;/a&gt; and &lt;a href=&quot;https://github.com/lmammino/distributed-jwt-cracker&quot;&gt;GitHub&lt;/a&gt; in case you want to simply download it or contribute.&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/how-to-crack-a-jwt-token-two-articles-about-distributed-computing-zeromq-node-js.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/how-to-crack-a-jwt-token-two-articles-about-distributed-computing-zeromq-node-js.png" width="1200" height="630"/></media:content><category>node-js</category><category>zeromq</category><category>distributed</category><category>collaboration</category><category>jwt</category><category>javascript</category><author>Luciano Mammino</author><comments>https://loige.co/how-to-crack-a-jwt-token-two-articles-about-distributed-computing-zeromq-node-js/#comments</comments><enclosure url="https://loige.co/og/how-to-crack-a-jwt-token-two-articles-about-distributed-computing-zeromq-node-js.png" length="0" type="image/png"/></item><item><title>My Universal JavaScript Web Applications talk at Codemotion Milan 2016</title><link>https://loige.co/my-universal-javascript-web-applications-talk-at-codemotion-milan-2016-2/</link><guid isPermaLink="true">https://loige.co/my-universal-javascript-web-applications-talk-at-codemotion-milan-2016-2/</guid><description>This blog post summarizes a talk about building a Universal JavaScript application with React given at Codemotion Milan 2016. It includes commentary for each slide, photos from Twitter, and a video recording. The post explains what Universal JavaScript is, its benefits, challenges, and walks through demo code to add server-side rendering and routing to a React app.</description><pubDate>Sat, 26 Nov 2016 09:53:55 GMT</pubDate><content:encoded>&lt;p&gt;Yesterday (25/11/2016) I had the pleasure of delivering a talk about Universal JavaScript at &lt;a href=&quot;http://milan2016.codemotionworld.com&quot;&gt;Codemotion Milan 2016&lt;/a&gt;. It was a great fun and I was very happy to meet such a big pool of technology enthusiasts and professionals all in one places. I’m already looking forward for the next edition!&lt;/p&gt;
&lt;h2 id=&quot;video&quot;&gt;Video&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt; (12-12-2016): a video recording of the talk has been published by the folks at Codemotion:&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://www.youtube.com/embed/9z7k3-Or7EA&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id=&quot;slides-deck&quot;&gt;Slides deck&lt;/h2&gt;
&lt;p&gt;If you are interested in my talk you can find the slides on &lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016&quot;&gt;Slides.com&lt;/a&gt;:&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;//slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016/embed&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id=&quot;commentary&quot;&gt;Commentary&lt;/h2&gt;
&lt;p&gt;Here follows also a quite detailed kind of commentary for every slide (from my notes), so you can easily understand all the concepts discussed during the presentation.&lt;/p&gt;
&lt;h4 id=&quot;1&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/1&quot;&gt;1.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Hello everybody, I am Luciano (also known as “&lt;a href=&quot;https://github.com/lmammino&quot;&gt;lmammino&lt;/a&gt;” or “&lt;a href=&quot;https://twitter.com/loige&quot;&gt;loige&lt;/a&gt;” on GitHub and Twitter).
I am a software engineer at &lt;a href=&quot;http://planet9energy.com&quot;&gt;Planet9 Energy&lt;/a&gt;, a new electricity provider that is focused
on using new technologies to give industrial and consumer customers more visibility over
their bills and at the same time enabling new ways to perform energy trading very efficiently.&lt;/p&gt;
&lt;p&gt;Me and my team are currently building most of the infrastructure using a serverless approach
and we make heavy use of AWS lambda and the serverless framework. If you are interested
in these topics please catch up with me after this talk.&lt;/p&gt;
&lt;p&gt;I am also the co-author of the book “&lt;a href=&quot;https://www.nodejsdesignpatterns.com&quot;&gt;Node.js Design Patterns Second Edition&lt;/a&gt;” together with &lt;a href=&quot;https://twitter.com/mariocasciaro&quot;&gt;Mario Casciaro&lt;/a&gt;. If you are interested in re-enforcing your knowledge of design patterns, and most importantly discover how you can get the best out of them in the Node.js and JavaScript land, this book is probably for you. For what concerns this talk, the book also features an entire chapter about Universal JavaScript.&lt;/p&gt;
&lt;h4 id=&quot;2&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/2&quot;&gt;2.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;So today we are going to be talking about Universal JavaScript for Web applications.&lt;/p&gt;
&lt;p&gt;First of all we will see what “universal” really means, then we will discuss who is currently using it and why. Then we will move into a quick overview of the main challenges to face when dealing with universal JavaScript applications. Finally, in the second part of this talk, we will see a practical example about how to build a Universal JavaScript Web Application. At first we will build the front-end only version and then by making it “universal”.&lt;/p&gt;
&lt;h4 id=&quot;3&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/3&quot;&gt;3.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;So, for some time, what we call today Universal JavaScript was recognised as “Isomorphic” JavaScript. After some discussions it seems that the JavaScript community agreed on using the term “Universal” instead. If you are interested in the full story you can read most of it at this link &lt;a href=&quot;http://bit.ly/universaljs&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Anyway, what do we really mean with the term “Universal”? I am going to phrase my own definition here… So please don’t take it as an academic one…&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Universal Javascript means writing JavaScript code that can run on different JavaScript runtimes over different contexts. For example on the Browser as well as on the Server.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;4&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/4&quot;&gt;4.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;But that’s not limited only to the web, for example we can talk about Universal JavaScript even when building desktop or mobile applications and some people are even attempting experiments to control hardware devices directly with JavaScript.
During the course of this talk we are going to focus only on Web development though.&lt;/p&gt;
&lt;h4 id=&quot;5&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/5&quot;&gt;5.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;What are the main advantages of Universal JavaScript? First of all it allows you to deal with a JavaScript only development environment. Having JavaScript both on the Browser and on the Server removes the cost of language switching. This of course happens with any Node.js application, even if not Universal. When it gets to universal you are going to have most of the same code shared between frontend and backend, so in that case your code base would probably contain less duplication and thus will result to be more maintainable.
Also with universal JavaScript you will achieve better Serach Engines Optimization, because the server will be able to render the full content of you pages and not just that but it will also be able to return proper http codes in any situation, so cases like “page not found” or “redirects” can be resolved correctly by Google and the other crawlers.
Finally we will also achieve a better “perceived” load time. This is a side effect of server rendering, because when the browser finish to download the HTML of the page it will have already most of the information needed to render the page, so the classical flickering effect of classic single page applications would be less likely to happen.&lt;/p&gt;
&lt;h4 id=&quot;6&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/6&quot;&gt;6.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Just to mention a few, the very first early adopter of Universal JavaScript were Netflix, Airbnb, Wordpress (that used this approach to build the &lt;a href=&quot;https://github.com/Automattic/wp-calypso&quot;&gt;new administration panel for wordpress.com&lt;/a&gt;) and Dropbox.&lt;/p&gt;
&lt;h4 id=&quot;7&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/7&quot;&gt;7.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;So yes, everything looks great, but if you already heard about it, you probably also heard that it’s very complicated…
Let’s see why many people think so…&lt;/p&gt;
&lt;h4 id=&quot;8&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/8&quot;&gt;8.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Well, there are some specific pain point to address when it comes to build a Universal application. First of all you will need to have a nice way to write your code (generally in the form of modules) once and make it available between the backend and the frontend. The two environments, even if similar, are not the same. For example they load files and resources in different ways so we need standards and tools in order to “transform” the code in a way that is loadable and functional in both environments.
The current open source solutions are &lt;a href=&quot;https://github.com/umdjs/umd&quot;&gt;UMD&lt;/a&gt;, which stands for Universal Module Definition, &lt;a href=&quot;https://github.com/systemjs/systemjs&quot;&gt;SystemJS&lt;/a&gt; that allows to load modules asynchronously and &lt;a href=&quot;http://browserify.org&quot;&gt;Browserify&lt;/a&gt; and &lt;a href=&quot;https://webpack.github.io&quot;&gt;Webpack&lt;/a&gt; as module builder for bringing CommonJs/Node.js modules to the browser.&lt;/p&gt;
&lt;h4 id=&quot;9&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/9&quot;&gt;9.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Another issue is universal rendering. When it comes to JavaScript heavy applications we build most of the HTML needed from JavaScript itself (generally using the concept of components). In a regular Single Page Application these components are rendered only by the browser, after the page is fully loaded. With Unviersal JavaScript we want to be able to perform the generation of the full HTML from the server before the page is served to the browser. All the major new framworks like React and Angular 2 supports way to achieve Universal Rendering and there’s a new interesting player in this field called Next.js.&lt;/p&gt;
&lt;h4 id=&quot;10&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/10&quot;&gt;10.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A similar problem is universal routing. We want both the browser and the server to be able to render specific view given specific urls. Ideally we don’t want any code duplication, so the same mechanism to define routes and actions should be defined once and should function in a seamless way in both environments.
There are several interesting libraries trying to address this problem and one of the most famous, at least in the React land, is React Router.&lt;/p&gt;
&lt;h4 id=&quot;11&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/11&quot;&gt;11.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Again a similar problems comes in relation to loading the data (often in the form of an API) needed by the application.
In these cases one of the most common solutions is to have an api that is accessible both from the server and the client and load it with an universal code base using a library like Axios or Universal Fetch.&lt;/p&gt;
&lt;h4 id=&quot;12&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/12&quot;&gt;12.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Finally one of the last big pain points is Universal State management. There is a tendency to define the full state of an application in a single object generally using libraries like Redux or Cerebral. We want to keep doing this in a way that is fully compatible and functional both on the server and the client.&lt;/p&gt;
&lt;h4 id=&quot;13&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/13&quot;&gt;13.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;And well yes, plain old JavaScript doesn’t seem to be enough these days. We often want to use some high level abstraction or language extension like Flow or JSX or even other new languages able to compile directly to JavaScript like TypeScript or Elm.
This is not strictly necessary but it might make the developer experience way better.&lt;/p&gt;
&lt;h4 id=&quot;14&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/14&quot;&gt;14.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Yeah I know the current JavaScript panorama sounds a bit too broad and scary…&lt;/p&gt;
&lt;h4 id=&quot;15&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/15&quot;&gt;15.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;But let’s stop complaining and let’s build something together… It doesn’t need to be perfect but I will show you that it’s totally possible to build a non trivial Universal application in about 30 minutes.&lt;/p&gt;
&lt;h4 id=&quot;16&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/16&quot;&gt;16.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The tools that we are going to use for this experiment are Webpack, React, ReactRouter and express.&lt;/p&gt;
&lt;h4 id=&quot;17&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/17&quot;&gt;17.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;I was for years a Judo practitioner and I am still a big fan of this sport, so we are going to build an application called Judo Heroes. I already published a version of this application, you can see the URL here (judo-heroes.herokuapp.com) and I also wrote an entire tutorial based on it on Scotch.io (bit.ly/judo-heroes-tutorial).&lt;/p&gt;
&lt;h4 id=&quot;18&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/18&quot;&gt;18.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;As you can see the application is very simple ad allows us to display some of the best Judo Olympic athletes and read some details about them: their nationality, the year of birth, some pictures and the list of all the medals they won.&lt;/p&gt;
&lt;h4 id=&quot;19&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/19&quot;&gt;19.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Let’s see how Universal comes into play with this app. If we load a specific athlete page, we can see, using the chrome developer tools all the loaded resources.&lt;/p&gt;
&lt;h4 id=&quot;20&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/20&quot;&gt;20.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Then, if from the interface we switch to another athlete, the application loads only the new resources. In this case the images for the new athlete.&lt;/p&gt;
&lt;h4 id=&quot;21&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/21&quot;&gt;21.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;And also, if we refresh the page, the server will render the full html for the athlete page straight away. We can see this here with a curl command.&lt;/p&gt;
&lt;h4 id=&quot;22&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/22&quot;&gt;22.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Ok, let’s start looking at some code. Fist of all let’s see out data set. For the sake of this tutorial we will keep things simple and rely on a JavaScript module that exports an array of athletes. Every athletes is an object which contains all the information we need in order to display an athlete: name, country, birth year, images, list of medals, etc.
We can easily require this module everywhere we want to access the data.&lt;/p&gt;
&lt;h4 id=&quot;23&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/23&quot;&gt;23.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Now let’s build all the React components that define our interface.&lt;/p&gt;
&lt;h4 id=&quot;24&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/24&quot;&gt;24.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The first component that we are going to see is the &lt;code&gt;Layout&lt;/code&gt; component, which has the goal of defining the markup of the global layout we want to use in our application. It contains a static header and a static footer and a variable content.&lt;/p&gt;
&lt;h4 id=&quot;25&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/25&quot;&gt;25.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;This is more or less how a component looks like in React. We basically needs to define a render function that receives some parameters (called props) and returns the markup needed to render the component view. This markup looks like a mix of HTML and JavaScript and it’s called &lt;em&gt;JSX&lt;/em&gt;. In this case we expect to see:&lt;/p&gt;
&lt;p&gt;a. An header section
b. A variable content (notice the variable &lt;code&gt;props.children&lt;/code&gt;)
c. And the footer section&lt;/p&gt;
&lt;h4 id=&quot;26&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/26&quot;&gt;26.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Now let’s move to the &lt;code&gt;IndexPage&lt;/code&gt; component page. This component has the goal to show a card based navigation bar that allows us to select an athlete.&lt;/p&gt;
&lt;h4 id=&quot;27&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/27&quot;&gt;27.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The first thing to notice is that we are importing our data module to get the list of all the athletes. Then inside our render method we iterate over this list and, for every athlete in the list, we reference another component called &lt;code&gt;AthletePreview&lt;/code&gt; passing to it all the data representing the current athlete.&lt;/p&gt;
&lt;h4 id=&quot;28&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/28&quot;&gt;28.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;So the &lt;code&gt;AthletePreview&lt;/code&gt; component represents a card in the navigation bar of the &lt;code&gt;IndexPage&lt;/code&gt;. Let’s jump to the code.&lt;/p&gt;
&lt;h4 id=&quot;29&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/29&quot;&gt;29.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Let’s use this component to understand better how React and its JSX syntax work.&lt;/p&gt;
&lt;p&gt;a. As I told you we have a function that has the goal of providing the JSX markup needed by React to render the component.
b. The main &lt;em&gt;tag&lt;/em&gt; that we use is &lt;code&gt;Link&lt;/code&gt; which represents a React Router component. This will make all the component &lt;em&gt;clickable&lt;/em&gt; and will link it to a specific React route. We will see later in greater detail how the routing functionality works. The only important thing you need to notice for now is that the attribute &lt;code&gt;to&lt;/code&gt; uses an interpolated variable to build the link reference. We reference here the &lt;code&gt;props&lt;/code&gt; object which will contain all the attributes passed to this component by the parent component.
c. Then we display the headshot of the athlete, again we access the object &lt;code&gt;props&lt;/code&gt; to fetch the picture for the current athlete.
d. We do the same to display the name of the athlete.
e. Finally we also define the markup to render a little medal icon and the count of the medals won by the athlete.&lt;/p&gt;
&lt;h4 id=&quot;30&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/30&quot;&gt;30.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Now let’s move to the &lt;code&gt;AthletePage&lt;/code&gt; which represents the detail page of an athlete.&lt;/p&gt;
&lt;h4 id=&quot;31&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/31&quot;&gt;31.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A lot of code here. But don’t worry this is the biggest component we will see today and at the end it’s quite simple. So let’s zoom into the important details.&lt;/p&gt;
&lt;h4 id=&quot;32&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/32&quot;&gt;32.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;This component as well has access to all our data. It receives the id of the current athlete to display in &lt;code&gt;props.params.id&lt;/code&gt;, data that will be populate by the routing layer given the current url.&lt;/p&gt;
&lt;p&gt;a. We use this information to verify if the current id really exists in our little static database object. If not we simply render a &lt;code&gt;NotFoundPage&lt;/code&gt; component that we will see later. If the athlete exists we will have all its data in the &lt;code&gt;athlete&lt;/code&gt; variable.
b. If we have found the athlete we first render a custom component called &lt;code&gt;AthletesMenu&lt;/code&gt;.
c. Then we have the markup that define the header of the page (the one with the big background image and the picture of the current athlete).&lt;/p&gt;
&lt;h4 id=&quot;33&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/33&quot;&gt;33.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;d. Then we have a the markup needed to render the athlete description.
e. Notice that inside this markup we reference another custom component called &lt;code&gt;Flag&lt;/code&gt; which is the one responsible for rendering the flag icon inside the description.
f. In the next section we iterate over all the athlete medals and display them…
g. Using a custom component called &lt;code&gt;Medal&lt;/code&gt;
h. The last bit is a link that redirects to the index page.&lt;/p&gt;
&lt;h4 id=&quot;34&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/34&quot;&gt;34.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;This is the &lt;code&gt;AthletesMenu&lt;/code&gt; component that we referenced in the previous component.&lt;/p&gt;
&lt;h4 id=&quot;35&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/35&quot;&gt;35.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In its code we access again to our data module and we iterate over it.&lt;/p&gt;
&lt;p&gt;a. For every athlete we reference a &lt;code&gt;Link&lt;/code&gt; component pointing to the athlete page. It’s worth noticing that we use the attribute &lt;code&gt;activeClassName&lt;/code&gt;. This is a very handy utility of the ReactRouter module that allows us to apply to the link a specific class to the link tag when the linked route matches the current URL. With this utility get very easy to create some CSS code to style active links differently from the other ones.&lt;/p&gt;
&lt;h4 id=&quot;36&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/36&quot;&gt;36.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;This is the &lt;code&gt;Flag&lt;/code&gt; component we mentioned some slides before.&lt;/p&gt;
&lt;h4 id=&quot;37&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/37&quot;&gt;37.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The code is very simple. We just need to use the &lt;code&gt;props.icon&lt;/code&gt; to render the image tag properly. We also have an optional prop called &lt;code&gt;showName&lt;/code&gt; that, if set to a &lt;em&gt;truthy&lt;/em&gt; value, tells the component to also display the name of the country along the flag icon.&lt;/p&gt;
&lt;h4 id=&quot;38&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/38&quot;&gt;38.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Finally let’s see our &lt;code&gt;Medal&lt;/code&gt; component.&lt;/p&gt;
&lt;h4 id=&quot;39&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/39&quot;&gt;39.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In this component, before the render function we have a little dictionary object that we use to map medal types ids to it’s literal description (‘G’ for ‘Gold’, ‘S’ for ‘Silver’, etc.). Then we reference all the properties we receive from the parent component to display the medal year, the city, the name of the competition and the category.&lt;/p&gt;
&lt;h4 id=&quot;40&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/40&quot;&gt;40.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Finally let’s have a look at out super simple &lt;code&gt;NotFoundPage&lt;/code&gt; component. This is probably the simplest one as we don’t reference any dynamic property but we just render some markup to display a very simple error page with a link to the index.&lt;/p&gt;
&lt;h4 id=&quot;41&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/41&quot;&gt;41.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Ok, enough React components! I hope you are not bored already…
Let’s move to the routing functionality.&lt;/p&gt;
&lt;h4 id=&quot;42&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/42&quot;&gt;42.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In our application we will have two different routes:&lt;/p&gt;
&lt;p&gt;a. The index page, mapped to the main route
b. and the athlete page which uses the athlete &lt;code&gt;id&lt;/code&gt; as parameter.&lt;/p&gt;
&lt;h4 id=&quot;43&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/43&quot;&gt;43.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;in our &lt;code&gt;Routes&lt;/code&gt; components we define these two routes. Using ReactRouter we can define the routes hierarchy using JSX.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We have a main route that links the &lt;code&gt;Layout&lt;/code&gt; component. This will make sure that every component will use our default layout.&lt;/li&gt;
&lt;li&gt;Then the common index route is associated to our &lt;code&gt;IndexPage&lt;/code&gt; component.&lt;/li&gt;
&lt;li&gt;We than map the &lt;code&gt;AthletePage&lt;/code&gt; component to the path &lt;code&gt;athlete/:id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;And finally we provide a fallback path that matches all the other routers and renders our &lt;code&gt;NotFoundPage&lt;/code&gt; component.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;44&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/44&quot;&gt;44.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Let’s create the real router component now.&lt;/p&gt;
&lt;p&gt;a. This component imports our previously defined hierarchy of routes.
b. It uses the hashHistory mechanism to detect the current router. We will see later what this really means.
c. We reference our routing hierarchy through the &lt;code&gt;routes&lt;/code&gt; attribute.
d. Finally we use a little function to scroll the page back up every time we move dynamically to a new route. This will make sure that the transition between one page an another looks natural.&lt;/p&gt;
&lt;h4 id=&quot;45&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/45&quot;&gt;45.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;So now we have React components and routing. Let’s combine them together and finalize our client app.&lt;/p&gt;
&lt;h4 id=&quot;46&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/46&quot;&gt;46.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The app-client represent our browser application.&lt;/p&gt;
&lt;p&gt;a. It loads our router
b. and renders it inside the tag with id &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;47&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/47&quot;&gt;47.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Let’s see how the main html of our application looks like&lt;/p&gt;
&lt;h4 id=&quot;48&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/48&quot;&gt;48.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;We basically have some regular meta headers and a link to a stylesheet. Then in the body:&lt;/p&gt;
&lt;p&gt;a. We have our &lt;code&gt;main&lt;/code&gt; tag which will contain all our react app
b. The bundled script that contains all the code needed to run our app in the frontend.&lt;/p&gt;
&lt;h4 id=&quot;49&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/49&quot;&gt;49.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Let’s how we can build this bundle using Babel and Webpack.&lt;/p&gt;
&lt;h4 id=&quot;50&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/50&quot;&gt;50.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Our Babel config looks extremely simple:&lt;/p&gt;
&lt;p&gt;a. We just need to specify that we want to transpile react code and EcmaScript 2015 to regular ES5 code.&lt;/p&gt;
&lt;p&gt;Our webpack config is a bit more elaborate:&lt;/p&gt;
&lt;p&gt;b. First thing we need to specify is the entry point of our app. Webpack will start to crawl through all the used dependencies starting from this file.
c. Then we specify where we want to output the resulting bundled file.
d. And finally we specify that we want to process every file in our source directory using babel.&lt;/p&gt;
&lt;h4 id=&quot;51&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/51&quot;&gt;51.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;To create our bundle we just need to call &lt;code&gt;webpack&lt;/code&gt; from the command line.&lt;/p&gt;
&lt;h4 id=&quot;52&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/52&quot;&gt;52.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The last bit we need before seeing our application working is to write a small server app using Express that allows us to serve the static files that compose our app at this stage. We can do this using the &lt;code&gt;Express.static&lt;/code&gt; middleware.&lt;/p&gt;
&lt;h4 id=&quot;53&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/53&quot;&gt;53.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Let’s finally test our app!&lt;/p&gt;
&lt;p&gt;(Show frontend only app, show routing with hashes, code only rendered on the client and 404 not understood)&lt;/p&gt;
&lt;h4 id=&quot;54&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/54&quot;&gt;54.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;So What we have done so far?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We defined our views combining a bunch of different React components&lt;/li&gt;
&lt;li&gt;We added routing using React Router&lt;/li&gt;
&lt;li&gt;We compiled our application for the browser using Babel and Webpack&lt;/li&gt;
&lt;li&gt;Then we executed the application served through a static Express server&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;55&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/55&quot;&gt;55.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Ok nothing so exiting so far, let’s now add Server Side Rendering and Routing!&lt;/p&gt;
&lt;h4 id=&quot;56&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/56&quot;&gt;56.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;When we executed our front-end only application you probably noticed that our URLS were looking a bit weird. The only changing part was prefixed by an hashtag symbol. That’s because we were using the &lt;code&gt;hashHistory&lt;/code&gt; mode in our router. This route works very well for frontend-only applications, because it makes shareable link pointing to the right dynamic section, even when in the server you only have an &lt;code&gt;index.html&lt;/code&gt; page.&lt;/p&gt;
&lt;p&gt;We need now to switch to full routes (without hashtags) and to do so we can simply change our &lt;code&gt;hashHistory&lt;/code&gt; to &lt;code&gt;browserHistory&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;57&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/57&quot;&gt;57.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Now we also want to convert our old &lt;code&gt;index.html&lt;/code&gt; to a generic &lt;em&gt;ejs&lt;/em&gt; template. Our new file looks almost identical, with the only exception that inside our &lt;code&gt;main&lt;/code&gt; block we have now an &lt;em&gt;ejs&lt;/em&gt; template variable called &lt;code&gt;markup&lt;/code&gt; that allows us to inject arbitrary html code into it. We are going to use this to inject the React generated markup when rendering from the server.&lt;/p&gt;
&lt;h4 id=&quot;58&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/58&quot;&gt;58.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Now the last step is to update our server application to support universal routing and rendering. To do so we need to import some libraries from React, ReactDom e ReactRouter. We also import our routes from our frontend-only app and the &lt;code&gt;NotFoundPage&lt;/code&gt; component.&lt;/p&gt;
&lt;p&gt;Finally we also enable the support for &lt;em&gt;ejs&lt;/em&gt; templates.&lt;/p&gt;
&lt;h4 id=&quot;59&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/59&quot;&gt;59.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Now let’s get to the most interesting part, let’s see how the universal routing and rendering works.&lt;/p&gt;
&lt;p&gt;The important part of the code here is the Express route defined with &lt;code&gt;app.get(&apos;*&apos;, (req, res) =&gt; {...})&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is an Express &lt;em&gt;catch-all&lt;/em&gt; route that will intercept all the &lt;em&gt;GET&lt;/em&gt; requests to every URL in the server (not previously matched to a static file). Inside this route, we take care of delegating the routing logic to the React Router &lt;code&gt;match&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;match&lt;/code&gt; accepts two parameters: the first one is a configuration object and the second is a callback function. The configuration object must have two keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;routes&lt;/code&gt;: used to pass the React Router routes configuration. Here, we are passing the exact same configuration that we used for the client-side rendering.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;location&lt;/code&gt;: This is used to specify the currently requested URL.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The callback function is called at the end of the matching. It will receive three arguments: &lt;code&gt;error&lt;/code&gt;, &lt;code&gt;redirectLocation&lt;/code&gt; and &lt;code&gt;renderProps&lt;/code&gt;. We can use them to determine what exactly the result of the match operation was.&lt;/p&gt;
&lt;p&gt;We can have four different cases that we need to handle:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The first case is when we have an error during the routing resolution. To handle this case, we simply return a 500 internal server error response to the browser.&lt;/li&gt;
&lt;li&gt;The second case is when we match a route that is a redirect route. In this case, we need to create a server redirect message (302 redirect) to tell the browser to go to the new destination (this is not really happening in our application because we are not using redirect routes in our React Router configuration, but it’s good to have it ready in case we decide to keep evolving our application).&lt;/li&gt;
&lt;li&gt;The third case is when we match a route and we have to render the associated component. In this case, the argument renderProps is an object that contains the data we need to use to render the component. The component we are rendering is RouterContext (contained in the React Router module), which is responsible for rendering the full component tree using the values in renderProps.&lt;/li&gt;
&lt;li&gt;The last case is when the route is not matched, and here we can simply return a 404 not found error to the browser.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is the core of our server- side routing mechanism and we use the ReactDOM &lt;code&gt;renderToString&lt;/code&gt; function to be able to render the HTML code that represents the component associated to the currently matched route.&lt;/p&gt;
&lt;p&gt;Finally, we inject the resulting HTML into the &lt;code&gt;index.ejs&lt;/code&gt; template we defined before to obtain the full HTML page that we send to the browser.&lt;/p&gt;
&lt;h4 id=&quot;60&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/60&quot;&gt;60.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Let’s test the app again.&lt;/p&gt;
&lt;p&gt;(Show universal routing and rendering working when changing and reloading pages).&lt;/p&gt;
&lt;h4 id=&quot;61&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/61&quot;&gt;61.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Quick recap about what was done in this presentation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a Single Page Application with React and React Router&lt;/li&gt;
&lt;li&gt;Add server side routing and rendering using React and React Router libraries in out Express app&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;62&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/62&quot;&gt;62.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;What can we do next to have a fully-fledged Universal app.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add Universal Data Retrieval&lt;/li&gt;
&lt;li&gt;Add Universal State Management&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;63&quot;&gt;&lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-milan-2016#/63&quot;&gt;63.&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Thanks everybody for being here!&lt;/p&gt;
&lt;h2 id=&quot;thanks&quot;&gt;Thanks&lt;/h2&gt;
&lt;p&gt;Big thanks to the organizers of the event for giving me this chance to be there on the stage. Also great thanks to my great friends Alessandro Cinelli (&lt;a href=&quot;https://twitter.com/cirpo&quot;&gt;@cirpo&lt;/a&gt;), Andrea Mangano (&lt;a href=&quot;https://twitter.com/andreaman87&quot;&gt;@andreaman87&lt;/a&gt;), Aleksandar Čambas and Peter Caulfield (&lt;a href=&quot;https://twitter.com/quasi_modal&quot;&gt;@quasi_modal&lt;/a&gt;) for reviewing my slide deck and for giving me tons of advices!&lt;/p&gt;
&lt;h3 id=&quot;some-photos-from-twitter&quot;&gt;Some photos from Twitter&lt;/h3&gt;
&lt;p&gt;Gigantic thanks also to whoever took pictures and shared them on Twitter, some here:&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;it&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;&lt;a href=&quot;https://twitter.com/loige&quot;&gt;@loige&lt;/a&gt; on stage &lt;a href=&quot;https://twitter.com/hashtag/codemotion?src=hash&quot;&gt;#codemotion&lt;/a&gt; Milan! Rock on! &lt;a href=&quot;https://t.co/9Y97YENhIG&quot;&gt;pic.twitter.com/9Y97YENhIG&lt;/a&gt;&lt;/p&gt;— cirpo (@cirpo) &lt;a href=&quot;https://twitter.com/cirpo/status/802170435425234948&quot;&gt;25 novembre 2016&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;it&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;It&apos;s time of &lt;a href=&quot;https://twitter.com/hashtag/universaljs?src=hash&quot;&gt;#universaljs&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/reactjs?src=hash&quot;&gt;#reactjs&lt;/a&gt; with &lt;a href=&quot;https://twitter.com/loige&quot;&gt;@loige&lt;/a&gt; &lt;a href=&quot;https://t.co/2XrAZFOBRe&quot;&gt;pic.twitter.com/2XrAZFOBRe&lt;/a&gt;&lt;/p&gt;— Andrea Mangano (@andreaman87) &lt;a href=&quot;https://twitter.com/andreaman87/status/802170179379752960&quot;&gt;25 novembre 2016&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;it&quot;&gt;&lt;p lang=&quot;it&quot; dir=&quot;ltr&quot;&gt;Ottimo talk, su &lt;a href=&quot;https://twitter.com/hashtag/reactjs?src=hash&quot;&gt;#reactjs&lt;/a&gt;. Forse le più belle slide mai viste. Chiare ed essenziali &lt;a href=&quot;https://twitter.com/hashtag/Codemotion?src=hash&quot;&gt;#Codemotion&lt;/a&gt; &lt;a href=&quot;https://twitter.com/loige&quot;&gt;@loige&lt;/a&gt; &lt;a href=&quot;https://t.co/DhCRV8NPMX&quot;&gt;pic.twitter.com/DhCRV8NPMX&lt;/a&gt;&lt;/p&gt;— Daniele Montagni (@dmontagni) &lt;a href=&quot;https://twitter.com/dmontagni/status/802182660189724672&quot;&gt;25 novembre 2016&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;I hope you liked this article and that you are now somehow confident that building universal JavaScript application is not that hard… you just need to start somewhere!
Feel free to leave any question or comment below on the comments box.&lt;/p&gt;
&lt;p&gt;Cheers, see you next time! 🍻&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/my-universal-javascript-web-applications-talk-at-codemotion-milan-2016-2.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/my-universal-javascript-web-applications-talk-at-codemotion-milan-2016-2.png" width="1200" height="630"/></media:content><category>slides</category><category>talk</category><category>node-js</category><category>javascript</category><category>react</category><author>Luciano Mammino</author><comments>https://loige.co/my-universal-javascript-web-applications-talk-at-codemotion-milan-2016-2/#comments</comments><enclosure url="https://loige.co/og/my-universal-javascript-web-applications-talk-at-codemotion-milan-2016-2.png" length="0" type="image/png"/></item><item><title>My Serverless &amp; AWS Lambda talk at Node.js Dublin January 2017</title><link>https://loige.co/my-serverless-aws-lambda-talk-at-nodejs-dublin-january-2017/</link><guid isPermaLink="true">https://loige.co/my-serverless-aws-lambda-talk-at-nodejs-dublin-january-2017/</guid><description>This post summarizes a talk about building a serverless architecture on AWS Lambda using the Serverless framework. It covers topics like authentication, authorization, testing, CI/CD, and cost monitoring. The presenters share lessons learned from real-world experience building a production serverless application.</description><pubDate>Tue, 14 Feb 2017 19:03:00 GMT</pubDate><content:encoded>&lt;p&gt;Last January I had the pleasure to share the stage with the great &lt;a href=&quot;https://twitter.com/Podgeypoos79&quot;&gt;Padraig O’Brien&lt;/a&gt; to talk about how we use Node.js, AWS Lambda and the Serverless framework at &lt;a href=&quot;https://planet9energy.com&quot;&gt;Planet9 Energy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The talk was hosted by the monthly &lt;a href=&quot;https://www.meetup.com/Dublin-Node-js-Meetup/events/236870576/&quot;&gt;Node.js Dublin Meetup&lt;/a&gt; at Intercom Dublin office, as usual, a very cool location for this kind of tech talks.&lt;/p&gt;
&lt;p&gt;Apart from having a great chance to show off my über cool Super Mario T-shirt for about 45 minutes, Podge and I had some good time discussing the following topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What does “&lt;strong&gt;Serverless&lt;/strong&gt;” mean and the &lt;a href=&quot;https://serverless.com&quot;&gt;Serverless framework&lt;/a&gt;?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security concerns&lt;/strong&gt; like how we achieved authentication and authorization in a serverless and stateless environment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code quality and Developer Experience&lt;/strong&gt; discussing how we do unit and functional tests, Continuous Integration and deployments.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;costs of a serverless infrastructure&lt;/strong&gt; and the various tools that can allow you to forecast your costs.&lt;/li&gt;
&lt;li&gt;Lessons learned and some interesting tips and tricks.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Considering the quite big audience, the number of questions and the stars received on the meetup page I’d say I am jubilant with the outcome of the talk, but of course, I am always eager to deep dive on these topics and discuss my findings with other enthusiasts.&lt;/p&gt;
&lt;p&gt;If you are curious you can check out &lt;a href=&quot;https://speakerdeck.com/lmammino/aws-lambda-and-serverless-framework-lessons-learned-while-building-a-serverless-company&quot;&gt;the slides of the talk on SpeakerDeck&lt;/a&gt; or watch the recording here below:&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://www.youtube.com/embed/90vV327JHho&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;And yeah, there are &lt;a href=&quot;https://www.meetup.com/Dublin-Node-js-Meetup/photos/all_photos/?photoAlbumId=27574272&quot;&gt;some beautiful pictures too&lt;/a&gt;! 😎&lt;/p&gt;
&lt;p&gt;Thanks to the organisers and the sponsors for inviting us to speak and supporting this fantastic event. Also thanks to Planet9 Energy for giving us the chance to work on these cool technologies and for encouraging us to deliver these kinds of talks.&lt;/p&gt;
&lt;p&gt;If you want to make me even happier, or if you have any question about the talk, feel more than welcome to leave a comment here!&lt;/p&gt;
&lt;p&gt;Until next time!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/my-serverless-aws-lambda-talk-at-nodejs-dublin-january-2017.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/my-serverless-aws-lambda-talk-at-nodejs-dublin-january-2017.png" width="1200" height="630"/></media:content><category>slides</category><category>talk</category><category>node-js</category><category>javascript</category><category>aws-lambda</category><category>serverless</category><author>Luciano Mammino</author><comments>https://loige.co/my-serverless-aws-lambda-talk-at-nodejs-dublin-january-2017/#comments</comments><enclosure url="https://loige.co/og/my-serverless-aws-lambda-talk-at-nodejs-dublin-january-2017.png" length="0" type="image/png"/></item><item><title>2016 - A year in review</title><link>https://loige.co/2016-a-year-in-review/</link><guid isPermaLink="true">https://loige.co/2016-a-year-in-review/</guid><description>A personal review of 2016 highlights career growth through a new job, open source contributions, conference talks, and co-authoring a Node.js book. The post also covers learning new technologies like Elixir and AWS, while noting failures like lack of focus on a side project.</description><pubDate>Sat, 24 Dec 2016 18:13:18 GMT</pubDate><content:encoded>&lt;p&gt;2016 is almost over and I just realised that it has been one of my most productive and exciting years ever. With that in mind I would love to write a recap of all the good and bad things (mostly from a career perspective) that happened in my life during this year. I want to keep track and benchmark my productivity over the coming years. This might be boring for you to read but I hope it’s going to serve myself as a good motivation to keep doing better over the years, both in terms of career and quality of life.&lt;/p&gt;
&lt;h2 id=&quot;co-authoring-a-book-about-nodejs-and-design-patterns&quot;&gt;Co-authoring a book about Node.js and Design patterns&lt;/h2&gt;
&lt;p&gt;One of the biggest achievements this year (and possibly during the course of my entire life) was to co-author a technical book!
From November last year to July this year I helped the great &lt;a href=&quot;https://twitter.com/mariocasciaro&quot;&gt;Mario Casciaro&lt;/a&gt; and &lt;em&gt;Packt Publishing&lt;/em&gt; joining them as co-author to revise “&lt;strong&gt;Node.js Design Patterns&lt;/strong&gt;” and come up with a shiny &lt;a href=&quot;https://www.nodejsdesignpatterns.com&quot;&gt;second edition&lt;/a&gt;.
Being part of this initiative served me a double value. First of all, it was an amazing learning experience, I had to get my hands dirty with so many &lt;a href=&quot;/tag/node-js&quot;&gt;Node.js&lt;/a&gt; details and patterns and nail most of them in a relatively short timespan. Now I feel like I’m fully aware of what’s going on under the hood of Node.js and I am confident I can write pretty decent Node.js code using the right patterns for specific needs. In the second place, being a book author gave me much more visibility as a Node.js enthusiast and now I have more chances to interact with other people interested in this trending topic.&lt;/p&gt;
&lt;p&gt;If you are curious about Node.js and Design Patterns you can check out the official website of the book at: &lt;a href=&quot;https://www.nodejsdesignpatterns.com&quot;&gt;https://www.nodejsdesignpatterns.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nodejsdesignpatterns.com&quot;&gt;&lt;img alt=&quot;Book Cover Node.js design patterns second edition Mario Casciaro Luciano Mammino Packt Publishing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;405&quot; height=&quot;500&quot; src=&quot;https://loige.co/_astro/book-cover-nodejs-design-patterns-second-edition-mario-casciaro-luciano-mammino-small.CWYcusw9_1hUrSA.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;career&quot;&gt;Career&lt;/h2&gt;
&lt;p&gt;In terms of career, this October I also moved from my position of Senior PHP Developer at &lt;em&gt;Smartbox&lt;/em&gt; to a new role as Senior Software Developer at &lt;a href=&quot;http://planet9energy.com&quot;&gt;Planet9 Energy&lt;/a&gt;. I am still pretty new in the company, but so far this change has been very exciting for a bunch of reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I get to work with a team of insanely skilled professionals like &lt;a href=&quot;https://twitter.com/hughsheehy&quot;&gt;@hughsheehy&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/tech_fort&quot;&gt;@tech_fort&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/Podgeypoos79&quot;&gt;@Podgeypoos79&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/quasi_modal&quot;&gt;@quasi_modal&lt;/a&gt;, Aleksandar Čambas (who doesn’t like Twitter!) and &lt;a href=&quot;https://twitter.com/katavic_d&quot;&gt;@katavic_d&lt;/a&gt;. It’s a pleasure to learn from them and with them everyday!&lt;/li&gt;
&lt;li&gt;Most of my work is in Node.js so I can stick to a language (JavaScript) I am loving and keep improving my knowledge and experience with it.&lt;/li&gt;
&lt;li&gt;I can be part of many architectural discussions and decisions about how we evolve a very sophisticated product that is managing an insane amount of data.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I really look forward to keep doing my best next year and see some of the things we are building going live!&lt;/p&gt;
&lt;h2 id=&quot;conferences-and-meet-ups-talks&quot;&gt;Conferences and meet-ups talks&lt;/h2&gt;
&lt;p&gt;This year I did my first official conference talk at Codemotion Milan in November. If you are interested in Universal JavaScript and React you can find all the details (slides, video and notes) here: &lt;a href=&quot;http://loige.co/my-universal-javascript-web-applications-talk-at-codemotion-milan-2016-2/&quot;&gt;My Universal JavaScript Web Applications talk at Codemotion Milan 2016&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I was quite satisfied with the result of the talk, even if I think I still have a lot to improve.&lt;/p&gt;
&lt;p&gt;This was the official feedback from the organizers and the audience:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;220 people attended your session, among them 68% rated it as “Good”, 30% as “Neutral” and 2% as “Bad”.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In march I also made a talk at the PHP Dublin meet-up group about web application performance. Check it out here: &lt;a href=&quot;http://loige.co/6-tips-to-build-fast-web-applications-php-dublin-march-2016-talk/&quot;&gt;6 Tips to Build Fast Web Applications (Php Dublin March 2016 Talk)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I really enjoyed both experiences and I hope I will have more chances next year to deliver tech talks in meet-ups and conferences around Europe.&lt;/p&gt;
&lt;h2 id=&quot;blog-posts&quot;&gt;Blog posts&lt;/h2&gt;
&lt;p&gt;I have to admit this year I wasn’t a very prolific author, I guess the book drained all my energies during my free time. Anyway, I still managed to write some posts. Here are the most interesting ones (based on actual reading stats):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://loige.co/extracting-data-from-wikipedia-using-curl-grep-cut-and-other-bash-commands/&quot;&gt;Extracting data from Wikipedia using curl, grep, cut and other shell commands&lt;/a&gt; (~18.000 views)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://loige.co/gulp-and-ftp-update-a-website-on-the-fly/&quot;&gt;Gulp and FTP: update a website “on the fly”&lt;/a&gt; (~7.000 views)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://loige.co/to-promise-or-to-callback-that-is-the-question/&quot;&gt;To promise or to callback? That is the question…&lt;/a&gt; (~3.000 views)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://loige.co/introducing-gulp-cozy-manage-your-gulp-tasks-in-a-cozier-way/&quot;&gt;Introducing Gulp cozy - Manage your gulp tasks in a cozier way&lt;/a&gt; (~2.000 views)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also it’s worth noticing that an article from 2015 is still driving a significant portion of traffic: &lt;a href=&quot;http://loige.co/developing-a-web-application-with-lumen-and-mysql/&quot;&gt;Developing a web application with Lumen and MySql&lt;/a&gt; (~20.000 views).&lt;/p&gt;
&lt;p&gt;Even considering such small amount of posts, the blog reached an impressive total of about 90.000 page views.&lt;/p&gt;
&lt;h2 id=&quot;external-posts-and-interviews&quot;&gt;External posts and Interviews&lt;/h2&gt;
&lt;p&gt;I also had the time (and the pleasure) to keep going with some interesting collaboration with websites I love like &lt;a href=&quot;https://scotch.io/&quot;&gt;Scotch.io&lt;/a&gt; and &lt;a href=&quot;https://community.risingstack.com/&quot;&gt;RisingStack&lt;/a&gt;. These are the posts that I enjoyed writing for external websites:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://scotch.io/tutorials/react-on-the-server-for-beginners-build-a-universal-react-and-node-app&quot;&gt;React on the Server for Beginners: Build a Universal React and Node App&lt;/a&gt; (~56.000 views)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ZeroMQ &amp;#x26; Node.js Tutorial - Cracking JWT Tokens&lt;/strong&gt; &lt;a href=&quot;https://community.risingstack.com/zeromq-node-js-cracking-jwt-tokens-1/&quot;&gt;Part 1&lt;/a&gt; &amp;#x26; &lt;a href=&quot;https://community.risingstack.com/zeromq-node-js-cracking-jwt-tokens-part2/&quot;&gt;Part 2&lt;/a&gt; (~7.000 views in total)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also had the pleasure to have two interviews about being a software developer and a book author:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Usersnap: &lt;a href=&quot;http://usersnap.com/blog/developer-community-luciano-mammino/&quot;&gt;Meet the community: Luciano Mammino, software developer from Sicily&lt;/a&gt; (~1.000 views)&lt;/li&gt;
&lt;li&gt;Packt blog: &lt;a href=&quot;https://www.packtpub.com/books/content/nodejs-its-easy-get-things-done&quot;&gt;With Node.js, it’s easy to get things done&lt;/a&gt; (undisclosed stats)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, I’d love to mention that one of my best posts from 2015 has been translated to Italian and published on &lt;a href=&quot;http://html5today.it&quot;&gt;HTML5Today.it&lt;/a&gt;, “&lt;a href=&quot;http://html5today.it/tutorial/performance-6-regole-sviluppare-applicazioni-web/&quot;&gt;Performance: 6 regole per sviluppare applicazioni web&lt;/a&gt;”.&lt;/p&gt;
&lt;h2 id=&quot;open-sourcing&quot;&gt;Open Sourcing&lt;/h2&gt;
&lt;p&gt;This year I also spent some time working out some small open source contributions, mostly creating little Node.js libraries or command line utilities for different purposes. Here’s the complete list of the open source repository I have been working on sorted by the number of stars received:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Atinux/schema-inspector&quot;&gt;Atinux/schema-inspector&lt;/a&gt; (contribution): Schema-Inspector is an JSON API sanitisation and validation module.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/silas/node-consul&quot;&gt;silas/node-consul&lt;/a&gt; (contribution): Node.js Consul client&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/judo-heroes&quot;&gt;lmammino/judo-heroes&lt;/a&gt;: A React application to showcase rendering with Universal JavaScript&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/flickr-set-get&quot;&gt;lmammino/flickr-set-get&lt;/a&gt;: A simple command line app to download photos from a flickr set&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/distributed-jwt-cracker&quot;&gt;lmammino/distributed-jwt-cracker&lt;/a&gt;: An experimental distributed JWT token cracker built using Node.js and ZeroMQ&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/godaddy-dns&quot;&gt;lmammino/godaddy-dns&lt;/a&gt;: A Node.js script to programmatically update GoDaddy DNS records&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/indexed-string-variation&quot;&gt;lmammino/indexed-string-variation&lt;/a&gt;: Experimental JavaScript module to generate all possible variations of strings over an alphabet using an n-ary virtual tree&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/gulp-cozy&quot;&gt;lmammino/gulp-cozy&lt;/a&gt;: Manage your gulp tasks in a cozier way&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/jwt-cracker&quot;&gt;lmammino/jwt-cracker&lt;/a&gt;: Simple HS256 JWT token brute force cracker&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/ghost2hexo&quot;&gt;lmammino/ghost2hexo&lt;/a&gt;: A command line tool to convert Ghost json export to a set of source posts for Hexo&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/x2j-cli&quot;&gt;lmammino/x2j-cli&lt;/a&gt;: Node.js command line script to convert xml input into json output (can be piped easily)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/vtt-creator&quot;&gt;lmammino/vtt-creator&lt;/a&gt;: Very basic Node.js/JavaScript library to generate VTT open subtitles files&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/package-strip-deps&quot;&gt;lmammino/package-strip-deps&lt;/a&gt;: A little command line utility that allows to strip dependencies from a NPM package.json file&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;learning&quot;&gt;Learning&lt;/h2&gt;
&lt;p&gt;During the last 5 months I slowly started to have a look into the (quite new) &lt;a href=&quot;http://elixir-lang.org/&quot;&gt;Elixir programming language&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For those who never heard before, let me quote the official website:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Elixir is a dynamic, functional language designed for building scalable and maintainable applications.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Elixir leverages the Erlang VM, known for running low-latency, distributed and fault-tolerant systems, while also being successfully used in web development and the embedded software domain.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Why, you might wonder? In the last 2 or 3 year I wanted to spend some time with a pure functional language but Haskell, Clojure, Lisp and other more famous language never really convinced me different reasons. Elixir, for some weird reasons, immediately catch my attention. Plus, it seems to be competing quite well with other “new-shiny” languages:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.google.com/trends/explore?date=2008-01-01%202016-12-24&amp;#x26;q=%2Fm%2F0dsbpg6,%2Fm%2F0pl075p,%2Fm%2F03yb8hb&quot;&gt;&lt;img alt=&quot;Comparison trend Elixir, Rust and Clojure&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;512&quot; src=&quot;https://loige.co/_astro/google-trend-clojure-elixir-rust-comparison.BvDLcyv7_1gSLwH.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Finally I also have to admit that my friend &lt;a href=&quot;https://twitter.com/bit_shark&quot;&gt;@bit_shark&lt;/a&gt; had me brainwashed with “how cool Elixir is”! Thanks for that!&lt;/p&gt;
&lt;p&gt;Also some other honourable mentions in my learning path this year have been:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/&quot;&gt;AWS&lt;/a&gt; (mostly API Gateway, Lambda, Redshift, DynamoDB, S3, EC2, RDS, Route53 and Cloudfront)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://serverless.com/&quot;&gt;Serverless framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/tag/react/&quot;&gt;React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/tag/zeromq/&quot;&gt;ZeroMQ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A bit of Python and &lt;a href=&quot;https://scrapy.org/&quot;&gt;Scrapy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A bit of Docker&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;failures&quot;&gt;Failures&lt;/h2&gt;
&lt;p&gt;Well, so far so good, but… I have to admit it wasn’t all peaches and dandelions. There were some failures here and there and it’s good to take them into account.&lt;/p&gt;
&lt;p&gt;The first and more important failure was not being able to focus on a side project. There is a &lt;em&gt;kind-of-secret-project™&lt;/em&gt; I have been working on with my great friend &lt;a href=&quot;https://twitter.com/andreaman87&quot;&gt;@andreaman87&lt;/a&gt;. I think I prioritised and planned really badly the time I wanted to spend on this project and I kept delaying my tasks. That’s a bit of a shame and I need to apologise with Andrea for that!&lt;/p&gt;
&lt;p&gt;Also another failure has been in my non-tech life, I haven’t been able to train Brazilian Jiu Jitsu as much as I should have done and I feel like my game and my knowledge hasn’t improved a lot! I guess I am going to keep my white belt still for a while :D&lt;/p&gt;
&lt;h2 id=&quot;expectations-for-next-year&quot;&gt;Expectations for next year&lt;/h2&gt;
&lt;p&gt;Ok, it’s finally time to move to the good intentions for the next year! I have been very lengthy already so I’ll just sort this part out with a simple unordered checklist, I am already looking forward to see, in one year time, how many items will be crossed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keep improving my knowledge of Node.js and everything related&lt;/li&gt;
&lt;li&gt;Publish the first version of my side project with Andrea&lt;/li&gt;
&lt;li&gt;Getting better with AWS and the Serverless framework&lt;/li&gt;
&lt;li&gt;Move my blog to a static publishing engine and (possibly) use a serverless hosting approach&lt;/li&gt;
&lt;li&gt;Keep investing time on Elixir and build something with it&lt;/li&gt;
&lt;li&gt;Presentations and talks in conferences and meet-ups&lt;/li&gt;
&lt;li&gt;Get more proficient with VIM (Cheers to &lt;a href=&quot;https://twitter.com/quasi_modal&quot;&gt;@quasi_modal&lt;/a&gt; for giving me &lt;a href=&quot;https://leanpub.com/painless_vim&quot;&gt;an amazing book&lt;/a&gt; as Christmas present!)&lt;/li&gt;
&lt;li&gt;Keep open sourcing stuff&lt;/li&gt;
&lt;li&gt;Travel more!&lt;/li&gt;
&lt;li&gt;More serious and constant BJJ training! 👊&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Well, That’s all… I hope I didn’t bore you to death!
Anyway, &lt;strong&gt;I’d really love to know what was your biggest achievement in 2016&lt;/strong&gt;. If you feel like you want to share this information with me feel free to &lt;a href=&quot;https://twitter.com/loige&quot;&gt;write me on Twitter&lt;/a&gt; or to post a comment here! I’ll make sure to have a pint in your honour! :D&lt;/p&gt;
&lt;p&gt;“&lt;strong&gt;Merry X-Mas and Happy New Year&lt;/strong&gt;” to you all! 🎅🏻&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/2016-a-year-in-review.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/2016-a-year-in-review.png" width="1200" height="630"/></media:content><category>life</category><author>Luciano Mammino</author><comments>https://loige.co/2016-a-year-in-review/#comments</comments><enclosure url="https://loige.co/og/2016-a-year-in-review.png" length="0" type="image/png"/></item><item><title>My Universal JavaScript Web Applications talk at Codemotion Rome 2017</title><link>https://loige.co/my-universal-javascript-web-applications-talk-at-codemotion-rome-2017/</link><guid isPermaLink="true">https://loige.co/my-universal-javascript-web-applications-talk-at-codemotion-rome-2017/</guid><description>The author gave a talk on building universal JavaScript web apps at Codemotion Rome 2017. He updated his Judo Heroes demo to v2 with React 15.4, React Router 4, Webpack 2, and Express 5. The talk got positive feedback from the audience. Slides and video are linked.</description><pubDate>Tue, 11 Apr 2017 22:41:40 GMT</pubDate><content:encoded>&lt;p&gt;Last month (March 25th) I had the pleasure of delivering again my Universal JavaScript talk in a Codemotion Event, &lt;a href=&quot;http://rome2017.codemotionworld.com/&quot;&gt;this time in Rome&lt;/a&gt;.
As expected it was a super interesting event and it gave me the chance to meet fantastic people, attend inspiring talks and refine my presentation.&lt;/p&gt;
&lt;h2 id=&quot;judo-heroes-version-2&quot;&gt;Judo Heroes Version 2&lt;/h2&gt;
&lt;p&gt;For this occasion, I updated my common Universal JavaScript &lt;a href=&quot;https://github.com/lmammino/judo-heroes&quot;&gt;Judo Heroes&lt;/a&gt; to “&lt;a href=&quot;https://github.com/lmammino/judo-heroes-2&quot;&gt;Version 2&lt;/a&gt;”.&lt;/p&gt;
&lt;p&gt;I believe this new version looks a bit more polished and easy to understand, plus it features a number of other relevant changes and improvements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Updated to &lt;code&gt;Webpack 2&lt;/code&gt;, &lt;code&gt;React 15.4&lt;/code&gt;, &lt;code&gt;React Router 4&lt;/code&gt; and &lt;code&gt;Express 5&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Using pure components where possible&lt;/li&gt;
&lt;li&gt;Better structure of components&lt;/li&gt;
&lt;li&gt;Top-down data propagation&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;video&quot;&gt;Video&lt;/h2&gt;
&lt;p&gt;If you missed the event (or if you are simply curious to hear my “&lt;em&gt;sicilian-english&lt;/em&gt;” accent 👌) you can check out the &lt;a href=&quot;https://www.youtube.com/watch?v=0VEwRFP8WtI&quot;&gt;video recording&lt;/a&gt; of the talk, just published by the lovely folks at Codemotion:&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://www.youtube.com/embed/0VEwRFP8WtI&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id=&quot;slides-deck&quot;&gt;Slides deck&lt;/h2&gt;
&lt;p&gt;If you are interested in checking out the slides (and explore all the links in it!) you can find them on &lt;a href=&quot;http://slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-rome-2017&quot;&gt;Slides.com&lt;/a&gt;:&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;//slides.com/lucianomammino/universal-js-web-applications-with-react-codemotion-rome-2017/embed&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id=&quot;audience-opinion&quot;&gt;Audience opinion&lt;/h2&gt;
&lt;p&gt;I was very happy to know that the feedback from the audience was pretty awesome, let me quote the email I received from the organisers:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;At this edition of Codemotion Rome we’ve tried to get the most out of attendees feedback by gathering as candid opinions as possible.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Right after your talk “Universal JavaScript Web Applications with React” we asked the attendees to express their evaluation rating it as “Good”, “Neutral” or “Bad”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;122 people attended your session, among them, 80% rated it as “Good”, 20% as “Neutral” and 1% as “Bad”&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Such a shame I couldn’t make that 1 or 2 people happy, but that only means that there is still room for improvement, I’ll try harder next time :)&lt;/p&gt;
&lt;h2 id=&quot;thanks&quot;&gt;Thanks&lt;/h2&gt;
&lt;p&gt;As usual, the biggest &lt;em&gt;thank you&lt;/em&gt; goes to the organisers of the event for giving me another precious chance to be there on the stage. Then, huge thanks to my great friends Alessandro Cinelli (&lt;a href=&quot;https://twitter.com/cirpo&quot;&gt;@cirpo&lt;/a&gt;), Andrea Mangano (&lt;a href=&quot;https://twitter.com/andreaman87&quot;&gt;@andreaman87&lt;/a&gt;), Aleksandar Čambas and Peter Caulfield (&lt;a href=&quot;https://twitter.com/quasi_modal&quot;&gt;@quasi_modal&lt;/a&gt;) for reviewing my slide deck and for giving me invaluable advice!&lt;/p&gt;
&lt;h2 id=&quot;next-events&quot;&gt;Next events&lt;/h2&gt;
&lt;p&gt;The Universal JavaScript fun is not over for me this year. I will be attending the following conferences soon:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://frontendunited.org/&quot;&gt;Frontend United Athens&lt;/a&gt; (26-27 May, talk)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://2017.websummercamp.com/&quot;&gt;Web Summer Camp Rovinj&lt;/a&gt; (30 Aug – 2 Sept, workshop)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Either if you were among the audience or if you just found out about my talk or my slides, I hope you enjoied the content and the examples and that you are now somehow confident that building universal JavaScript application is not that hard… you just need to start somewhere!&lt;/p&gt;
&lt;p&gt;Feel free to leave any question or comment below in the comments section.&lt;/p&gt;
&lt;p&gt;See you soon! 🤘&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/my-universal-javascript-web-applications-talk-at-codemotion-rome-2017.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/my-universal-javascript-web-applications-talk-at-codemotion-rome-2017.png" width="1200" height="630"/></media:content><category>slides</category><category>talk</category><category>react</category><category>javascript</category><category>node-js</category><author>Luciano Mammino</author><comments>https://loige.co/my-universal-javascript-web-applications-talk-at-codemotion-rome-2017/#comments</comments><enclosure url="https://loige.co/og/my-universal-javascript-web-applications-talk-at-codemotion-rome-2017.png" length="0" type="image/png"/></item><item><title>Unshorten (expand) short URLs with Node.js</title><link>https://loige.co/unshorten-expand-short-urls-with-node-js/</link><guid isPermaLink="true">https://loige.co/unshorten-expand-short-urls-with-node-js/</guid><description>This article explains how short URLs work and provides code examples to expand them in Node.js using request module or tall library. It covers basics of URL redirection, shows how to disable auto-redirect in request module, and introduces tall - a promise-based Node.js library to unshorten URLs.</description><pubDate>Fri, 31 Mar 2017 23:23:09 GMT</pubDate><content:encoded>&lt;p&gt;Short URLs have been an invaluable tool for social media marketing for so many years and we are now used to seeing them everywhere. Most of the credit probably goes to &lt;em&gt;URL shorteners&lt;/em&gt; services like &lt;a href=&quot;https://bitly.com&quot;&gt;Bit.ly&lt;/a&gt;, &lt;a href=&quot;https://goo.gl/&quot;&gt;Goo.gl&lt;/a&gt;, &lt;a href=&quot;https://yourls.org/&quot;&gt;YOURLS&lt;/a&gt; and &lt;a href=&quot;https://www.rebrandly.com&quot;&gt;Rebrandly&lt;/a&gt; that popularised the concept and made easy for everyone to start creating short URLs.&lt;/p&gt;
&lt;p&gt;When working with URLs in some automation scenarios like analytics, information crawling, data retrieval, etc. it can be important to &lt;em&gt;resolve&lt;/em&gt; (or “&lt;em&gt;unshorten&lt;/em&gt;” or “&lt;em&gt;expand&lt;/em&gt;”) short URLs, which means retrieving the original long URL.&lt;/p&gt;
&lt;p&gt;In this article, we are going to see how short URLs work and how we can “expand” them into their original URL.&lt;/p&gt;
&lt;h2 id=&quot;how-short-urls-work&quot;&gt;How short URLs work&lt;/h2&gt;
&lt;p&gt;A short URLs is a regular URL that most of the time results very short by following a very simple format:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;http://&amp;#x3C;domain&gt;/&amp;#x3C;id&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;http://&lt;domain&gt;/&lt;id&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The shorter the &lt;code&gt;domain&lt;/code&gt; and the &lt;code&gt;id&lt;/code&gt; (often called also &lt;code&gt;slashtag&lt;/code&gt;), the shorter will, of course, be the URL (e.g. &lt;a href=&quot;http://loige.link/b&quot;&gt;&lt;code&gt;http://loige.link/b&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;What happens behind the scene of an URL shortener service is that there is a big database table that contains a map of all the existing short URLs and the related full-length URLs.&lt;/p&gt;
&lt;p&gt;A URL shortener service lookup table might look like the following:&lt;/p&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Domain&lt;/th&gt;&lt;th&gt;Id&lt;/th&gt;&lt;th&gt;Url&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;loige.link&lt;/td&gt;&lt;td&gt;b&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://www.nodejsdesignpatterns.com/&quot;&gt;https://www.nodejsdesignpatterns.com/&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;loige.link&lt;/td&gt;&lt;td&gt;gh&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://github.com/lmammino&quot;&gt;https://github.com/lmammino&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;rebrand.ly&lt;/td&gt;&lt;td&gt;luciano-tw&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://twitter.com/loige&quot;&gt;https://twitter.com/loige&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;…&lt;/td&gt;&lt;td&gt;…&lt;/td&gt;&lt;td&gt;…&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Note that in this example the table supports multiple domains and that the pair &lt;code&gt;domain&lt;/code&gt;-&lt;code&gt;id&lt;/code&gt; must be unique in the table.&lt;/p&gt;
&lt;p&gt;URL shorteners have to expose a web server which will be reached through all the domains mapped (in fact, most of the URL shortener services — like Rebrandly — supports different domains or even the possibility to associate your own branded domain).&lt;/p&gt;
&lt;p&gt;For every request that satisfies the short URL format, &lt;code&gt;domain&lt;/code&gt; and &lt;code&gt;id&lt;/code&gt; are extracted and a query is executed against the database to search for the corresponding long URL. Finally, if a match is found, the web server responds with a redirect message, sending the browser of the user to the corresponding long URL.&lt;/p&gt;
&lt;h2 id=&quot;resolving-short-urls&quot;&gt;Resolving short URLs&lt;/h2&gt;
&lt;p&gt;URL shorteners need to talk with browsers so they have to work as any other web server adopting the HTTP standard. The following diagram illustrates how the HTTP protocol is used when a user clicks a short URL:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How short URL services work&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;691&quot; height=&quot;166&quot; src=&quot;https://loige.co/_astro/how-short-url-services-work-loige-nodejs.DOmtZzjp_ZwtUmz.webp&quot; &gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A user clicks on a short URL and the browser issues a &lt;strong&gt;GET&lt;/strong&gt; request to that URL.&lt;/li&gt;
&lt;li&gt;The request hits the short URL service server which executes a look-up on its database to find the associated long URL. The long URL is returned as a redirect response to the user browser which means an &lt;code&gt;HTTP 301 Moved Permanently&lt;/code&gt; response using the header &lt;code&gt;Location&lt;/code&gt; to specify the new (long) URL.&lt;/li&gt;
&lt;li&gt;The browser automatically follows the redirect response issuing a new &lt;strong&gt;GET&lt;/strong&gt; request to the long URL displaying the content of that URL to the user.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is what happens when a user through a browser deals with a short URL, everything happens behind the scenes and the user won’t even notice that there was an exchange with a short URL server.&lt;/p&gt;
&lt;p&gt;Simple enough, right?&lt;/p&gt;
&lt;h2 id=&quot;resolving-short-urls-in-nodejs&quot;&gt;Resolving short URLs in Node.js&lt;/h2&gt;
&lt;p&gt;Now that we know how short URL services work, it shouldn’t be hard to create a Node.js script that is capable of resolving any type of short URL.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;request&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;uri&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;http://bit.ly/2fR0xVj&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;uri&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;uri&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;followRedirect&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;httpResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;httpResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;headers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;location&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;uri&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;var request = require(&amp;#x27;request&amp;#x27;)var uri = &amp;#x27;http://bit.ly/2fR0xVj&amp;#x27;request(  {    uri: uri,    followRedirect: false,  },  function (err, httpResponse) {    if (err) {      return console.error(err)    }    console.log(httpResponse.headers.location || uri)  },)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;For simplicity, in this script, we are using the &lt;a href=&quot;https://www.npmjs.com/package/request&quot;&gt;&lt;code&gt;request&lt;/code&gt; module&lt;/a&gt; to perform the HTTP request. By default, this library follows redirects so we need to explicitly disable this behaviour by specifying the option &lt;code&gt;followRedirect: false&lt;/code&gt;. By doing so we have an opportunity to catch a redirect response in our callback and so we can read its &lt;code&gt;Location&lt;/code&gt; header which will represent the expanded URL.&lt;/p&gt;
&lt;p&gt;In case we are not dealing with a short URL, this script will print back the original URL passed to the function.&lt;/p&gt;
&lt;h2 id=&quot;a-promise-based-dependency-free-nodejs-library-for-expanding-short-urls&quot;&gt;A Promise-based, dependency free, Node.js library for expanding short URLs&lt;/h2&gt;
&lt;p&gt;You can easily adapt the code above to work with your specific use case, but if you want a ready-made and easy to use URL-unshortener NPM library you can trust a library I recently published called &lt;a href=&quot;https://www.npmjs.com/package/tall&quot;&gt;&lt;code&gt;tall&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tall&lt;/code&gt; is a dependency-free, promise-based library that allows you to easily resolve a short URL and get its corresponding long URL.&lt;/p&gt;
&lt;p&gt;To understand how easy to use &lt;code&gt;tall&lt;/code&gt; is, just check out this ES2015 sample usage:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;tall&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;tall&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;tall&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;http://www.loige.link/codemotion-rome-2017&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;unshortenedUrl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Tall url&apos;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;unshortenedUrl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;AAAW 👻&apos;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { tall } from &amp;#x27;tall&amp;#x27;tall(&amp;#x27;http://www.loige.link/codemotion-rome-2017&amp;#x27;)  .then((unshortenedUrl) =&gt; console.log(&amp;#x27;Tall url&amp;#x27;, unshortenedUrl))  .catch((err) =&gt; console.error(&amp;#x27;AAAW 👻&amp;#x27;, err))&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;More examples are available on &lt;a href=&quot;https://github.com/lmammino/tall&quot;&gt;the official repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;bonus-resolving-short-urls-with-curl&quot;&gt;Bonus: Resolving short URLs with CURL&lt;/h2&gt;
&lt;p&gt;Of course, you can also use the evergreen CURL to issue the HTTP request for a short URL and then read the &lt;code&gt;Location&lt;/code&gt; header to retrieve the long URL:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--head&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;http://bit.ly/2fR0xVj&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;curl --head &amp;#x22;http://bit.ly/2fR0xVj&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This will output something like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;CURL unshorten short URL output&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;602&quot; height=&quot;489&quot; src=&quot;https://loige.co/_astro/curl-unshorten-short-url-location-header-loige-nodejs.D5tv2w7c_Z1t878x.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;As you can see the &lt;code&gt;Location&lt;/code&gt; header reports our long URL.&lt;/p&gt;
&lt;p&gt;If you are a &lt;code&gt;bash&lt;/code&gt; and &lt;em&gt;Unix&lt;/em&gt; lover you are probably already thinking to pipe this output to &lt;code&gt;grep&lt;/code&gt; and other unix command line tools to extract only the long URL out of the full output. If you are curious about this kind of approach you can read a similar article I previously wrote titled “&lt;a href=&quot;http://loige.co/extracting-data-from-wikipedia-using-curl-grep-cut-and-other-bash-commands/&quot;&gt;Extracting data from Wikipedia using curl, grep, cut and other shell commands&lt;/a&gt;”.&lt;/p&gt;
&lt;h2 id=&quot;recap&quot;&gt;Recap&lt;/h2&gt;
&lt;p&gt;In this simple article, we learned how short URL services work and thus how we can use them in a programmatic way if we need to know the associated long URL.&lt;/p&gt;
&lt;p&gt;I hope this was interesting for you and that you had fun reading the article and the code examples.&lt;/p&gt;
&lt;p&gt;As usual, I’d love to have your opinion and know if you plan to use this knowledge or the &lt;code&gt;tall&lt;/code&gt; library in one of your next projects. Feel more than welcome to let me know this in the comments!&lt;/p&gt;
&lt;p&gt;See you next time!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/unshorten-expand-short-urls-with-node-js.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/unshorten-expand-short-urls-with-node-js.png" width="1200" height="630"/></media:content><category>node-js</category><category>library</category><category>javascript</category><author>Luciano Mammino</author><comments>https://loige.co/unshorten-expand-short-urls-with-node-js/#comments</comments><enclosure url="https://loige.co/og/unshorten-expand-short-urls-with-node-js.png" length="0" type="image/png"/></item><item><title>My Serverless talk at Shift conference in Split</title><link>https://loige.co/my-serverless-talk-at-shift-conference-in-split/</link><guid isPermaLink="true">https://loige.co/my-serverless-talk-at-shift-conference-in-split/</guid><description>Luciano Mammino recounts his experience speaking at the Shift conference in Split, Croatia about Serverless architecture and its pros and cons. He provides links to his talk video, slides, and a Twitter moment.</description><pubDate>Thu, 15 Jun 2017 13:49:59 GMT</pubDate><content:encoded>&lt;p&gt;This June, I had an amazing experience talking again about Serverless and how we use it at &lt;a href=&quot;https://planet9energy.com/&quot;&gt;Planet 9 Energy&lt;/a&gt; at the recent &lt;a href=&quot;http://shift.codeanywhere.com/index2017.html&quot;&gt;Shift Conference&lt;/a&gt; in Split, Croatia.&lt;/p&gt;
&lt;p&gt;In my talk titled “&lt;strong&gt;Serverless: The pros and cons of building a company
without infrastructure&lt;/strong&gt;”, I tried to address what Serverless is and why is becoming such a big thing, also exploring what I believe are the pros and cons of this new paradigm.&lt;/p&gt;
&lt;p&gt;The experience was great and I was super happy to have a chance to share the stage with extraordinary people in the industry such as: &lt;a href=&quot;https://twitter.com/codepo8&quot;&gt;Chris Heilmann&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/delorenzo&quot;&gt;Ike DeLorenzo&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/RChristiani&quot;&gt;Ryan Christiani&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/lc512k&quot;&gt;Laura Carvajal&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/akicolovic&quot;&gt;Aki Colovic&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/mantrakbeg&quot;&gt;Demir Selmanovic&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/pistenprinz&quot;&gt;Christoph Reinartz&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/dotansimha&quot;&gt;Dotan Simha&lt;/a&gt; and many others!&lt;/p&gt;
&lt;p&gt;I really recommend you to &lt;a href=&quot;https://www.youtube.com/channel/UCg1D4s1aLJVXMvYpBCh6_qA&quot;&gt;watch their talks&lt;/a&gt; and follow them on Twitter.&lt;/p&gt;
&lt;p&gt;Also, I have to give a big “THANK YOU” to &lt;a href=&quot;https://twitter.com/ivanburazin&quot;&gt;Ivan Burazin&lt;/a&gt; for organising this event and for inviting me to talk.&lt;/p&gt;
&lt;h2 id=&quot;video&quot;&gt;Video&lt;/h2&gt;
&lt;p&gt;If you missed my talk (or if you really want to hear my curious “&lt;em&gt;sicilian-english&lt;/em&gt;” accent again! 😅) you can check out the &lt;a href=&quot;https://www.youtube.com/watch?v=WunJFMfN2p8&quot;&gt;video recording&lt;/a&gt; of the talk, just published by the lovely folks at Shift. I have to say they made an amazing editing, I can almost feel like a professional:&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://www.youtube.com/embed/WunJFMfN2p8&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id=&quot;slides-deck&quot;&gt;Slides deck&lt;/h2&gt;
&lt;p&gt;As usual, my slides are available on &lt;a href=&quot;http://slides.com/lucianomammino/serverless-the-pros-and-cons-of-building-a-company-without-infrastructure-shift-2017&quot;&gt;Slides.com&lt;/a&gt;:&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;//slides.com/lucianomammino/serverless-the-pros-and-cons-of-building-a-company-without-infrastructure-shift-2017/embed&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id=&quot;twitter-moment&quot;&gt;Twitter moment&lt;/h2&gt;
&lt;p&gt;I also created a &lt;a href=&quot;https://twitter.com/i/moments/870877103423709184&quot;&gt;Twitter moment&lt;/a&gt; to collect all my tweets related to this amazing conference.&lt;/p&gt;
&lt;p&gt;I hope you will enjoy it:&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;twitter-moment&quot; href=&quot;https://twitter.com/i/moments/870877103423709184&quot;&gt;My experience at @shiftsplit 2017&lt;/a&gt; &lt;script async src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;&lt;/p&gt;
&lt;h2 id=&quot;closing-notes&quot;&gt;Closing notes&lt;/h2&gt;
&lt;p&gt;If you are interested in Serverless and you want to learn how to use it, you might be interested in booking a slot at &lt;a href=&quot;https://skillsmatter.com/conferences/8264-fullstack-2017-the-conference-on-javascript-node-and-internet-of-things&quot;&gt;Skills Matter FullStack conference&lt;/a&gt; that is going to be hosted in London from the 12th to the 14th of July.&lt;/p&gt;
&lt;p&gt;There, I will host a workshop together with the amazing &lt;a href=&quot;https://twitter.com/ChristosMatskas&quot;&gt;Christos Matskas&lt;/a&gt; from Microsoft about adopting Serverless on AWS (Lambda) and Azure (Functions). It’s going to be fun!&lt;/p&gt;
&lt;p&gt;Until next time! 🤙&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/my-serverless-talk-at-shift-conference-in-split.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/my-serverless-talk-at-shift-conference-in-split.png" width="1200" height="630"/></media:content><category>conferences</category><category>slides</category><category>speaking</category><category>serverless</category><category>javascript</category><category>node-js</category><author>Luciano Mammino</author><comments>https://loige.co/my-serverless-talk-at-shift-conference-in-split/#comments</comments><enclosure url="https://loige.co/og/my-serverless-talk-at-shift-conference-in-split.png" length="0" type="image/png"/></item><item><title>2017 - A year in review</title><link>https://loige.co/2017-a-year-in-review/</link><guid isPermaLink="true">https://loige.co/2017-a-year-in-review/</guid><description>In 2017, Luciano Mammino gave 17 conference talks, contributed to open source projects like Fastify and Middy, and learned new technologies like Terraform and Ansible. He looks forward to presenting more in 2018 and learning technologies like Rust, Elastic Search, and Kubernetes.</description><pubDate>Wed, 03 Jan 2018 18:59:58 GMT</pubDate><content:encoded>&lt;p&gt;2017 is over and it’s time to sit down and see what happened during this year. As I already did &lt;a href=&quot;https://loige.co/2016-a-year-in-review/&quot;&gt;last year&lt;/a&gt;, I would love to write a (potentially boring) recap of all the good and bad things (mostly from a career perspective) that happened in my life during this year.&lt;/p&gt;
&lt;p&gt;Last year I promised myself I would keep doing this as a way to keep track and benchmark my productivity over the coming years, so here I am to see how I performed!&lt;/p&gt;
&lt;h2 id=&quot;the-year-of-conference-talks&quot;&gt;The year of conference talks!&lt;/h2&gt;
&lt;p&gt;Let’s start with a big win! This was the year of conference talks (and workshops too!). I had to travel a fair bit around Europe and I created a dedicated &lt;a href=&quot;https://loige.co/speaking/&quot;&gt;speaking page&lt;/a&gt; to keep track of all the events I have been involved with and the related available material (slides, videos, repositories).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Luciano Mammino at CodeEurope Wroclaw&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1200&quot; height=&quot;675&quot; src=&quot;https://loige.co/_astro/loige-co-luciano-mammino-2017-a-year-in-review-conferences.Cj1zwLgf_1Mwhih.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Here’s the full list of the talks and workshop I had the pleasure to deliver in 2017:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;“AWS Lambda &amp;#x26; Serverless framework”&lt;/em&gt; at &lt;strong&gt;Node.js Meetup&lt;/strong&gt;, Dublin (January)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Universal JS Web Applications with React”&lt;/em&gt; at &lt;strong&gt;Codemotion&lt;/strong&gt;, Rome (March)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Building a Serverless company with Node.js, React and the Serverless framework”&lt;/em&gt; at &lt;strong&gt;JSDay&lt;/strong&gt;, Verona (May)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Universal Javascript”&lt;/em&gt; at &lt;strong&gt;Frontend United&lt;/strong&gt;, Athens (May)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Serverless, the pros and cons of building a company without infrastructure”&lt;/em&gt; at &lt;strong&gt;Shift Conference&lt;/strong&gt;, Split (June)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Deep Dive on Serverless Application Development (with Planet 9 Energy)”&lt;/em&gt; with Danilo Poccia from AWS and Padraig O’Brien from Planet 9 Energy at &lt;strong&gt;AWS Summit&lt;/strong&gt;, London (June)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Serverless: getting started with AWS Lambda Functions”&lt;/em&gt; (workshop) with Padraig O’Brien at &lt;strong&gt;Dublin.js Meetup&lt;/strong&gt;, Dublin (July)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Serverless: the battle of the giants”&lt;/em&gt; (workshop) with Christos Matskas from Microsoft at &lt;strong&gt;FullStack 2017&lt;/strong&gt;, London (July)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Universal JS web applications with React”&lt;/em&gt; (workshop) at &lt;strong&gt;Web Summer Camp&lt;/strong&gt;, Rovinj (September)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Serverless from the trenches”&lt;/em&gt; with Padraig O’Brien at &lt;strong&gt;AWS User Group&lt;/strong&gt;, Dublin (October)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Getting started with Serverless and AWS Lambda Functions”&lt;/em&gt; (workshop) at &lt;strong&gt;Codemotion&lt;/strong&gt;, Milan (November)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Cracking JWT tokens: a tale of magic, Node.JS and parallel computing”&lt;/em&gt; at &lt;strong&gt;Codemotion&lt;/strong&gt;, Milan (November)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Cracking JWT tokens: a tale of magic, Node.JS and parallel computing”&lt;/em&gt; at &lt;strong&gt;Node.js meetup&lt;/strong&gt;, Dublin (November)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“The future will be Serverless”&lt;/em&gt; at &lt;strong&gt;The Front Conf&lt;/strong&gt;, Munich (December)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Introducing Middy”&lt;/em&gt; (Lightning talk) at &lt;strong&gt;The Front Conf&lt;/strong&gt;, Munich (December)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Building a serverless company on AWS lambda and Serverless framework”&lt;/em&gt; with Padraig O’Brien at &lt;strong&gt;CodeEurope&lt;/strong&gt;, Wroclaw (December)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Cracking JWT tokens: a tale of magic, Node.JS and parallel computing”&lt;/em&gt; at &lt;strong&gt;CodeEurope&lt;/strong&gt;, Wroclaw (December)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;👍 Compared to 2016, I moved from 2 conferences talks to 17 (+750%), this is a pretty good WIN (and an awesome vanity metrics too 😇)!&lt;/p&gt;
&lt;p&gt;I am really curious to see what 2018 will bring on this regard!&lt;/p&gt;
&lt;h2 id=&quot;career&quot;&gt;Career&lt;/h2&gt;
&lt;p&gt;In December I finished my contract with Planet 9 Energy and I am very excited to start a new adventure as Solution Architect with &lt;a href=&quot;https://vectra.ai&quot;&gt;Vectra&lt;/a&gt; in Dublin. If you never heard about Vectra, this is what &lt;a href=&quot;https://vectra.ai/leadership&quot;&gt;Vectra about page&lt;/a&gt; has to say about it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Vectra offers the fastest way to detect and stop hidden cyberattackers – from cloud and data center workloads to user and IoT devices.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img alt=&quot;Vectra logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1692&quot; height=&quot;452&quot; src=&quot;https://loige.co/_astro/vectra-logo.Bj1cP_9i_Zgmvgy.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;The range of products offered by Vectra sounds extremely interesting and I am sure I will be exposed to super interesting topics like &lt;strong&gt;IT Security&lt;/strong&gt; and &lt;strong&gt;Machine Learning&lt;/strong&gt;, so I am absolutely thrilled to get started.&lt;/p&gt;
&lt;h2 id=&quot;the-year-of-side-projects&quot;&gt;The year of side projects&lt;/h2&gt;
&lt;p&gt;2017, wasn’t just the year of the conference talks, but also the year of &lt;em&gt;side-projects&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;I didn’t write a new book, but I had the real pleasure to be involved in four on-going side projects: &lt;a href=&quot;https://fullstackbulletin.com&quot;&gt;Fullstack bulletin&lt;/a&gt;, &lt;a href=&quot;https://serverlesslab.com&quot;&gt;Serverless Lab&lt;/a&gt;, &lt;a href=&quot;https://middy.js.org&quot;&gt;Middy&lt;/a&gt; and &lt;a href=&quot;https://www.fastify.io&quot;&gt;Fastify&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;fullstack-bulletin&quot;&gt;Fullstack bulletin&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://fullstackbulletin.com&quot;&gt;&lt;img alt=&quot;Fullstack bulletin website preview&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1200&quot; height=&quot;675&quot; src=&quot;https://loige.co/_astro/fullstack-bulletin-preview-loige-co-2017-a-year-in-review.CLeqnjgf_4PNfU.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fullstack bulletin&lt;/strong&gt; is a weekly newsletter &lt;a href=&quot;https://twitter.com/andreaman87&quot;&gt;Andrea Mangano&lt;/a&gt; and myself built to support ambitious fullstack developers to stay up to date with the latest trends and news. The idea is to collect 7 interesting links every week regarding topics such as Frontend/Backend web development, APIs, microservices, databases, scalability, but also web design, UI and UX. In every issue, aside from the links, you also get a famous &lt;em&gt;tech-related&lt;/em&gt; quote and a suggested tech book.&lt;/p&gt;
&lt;p&gt;The links are extracted automatically from the ones tweeted by Andrea and myself during the previous week, using a simple ranking algorithm.&lt;/p&gt;
&lt;p&gt;The project is totally &lt;a href=&quot;https://github.com/FullStackBulletin&quot;&gt;open sourced&lt;/a&gt; and built on top of serverless technologies (mostly AWS Lambda, Serverless framework and Cloudwatch).&lt;/p&gt;
&lt;h3 id=&quot;serverless-lab&quot;&gt;Serverless lab&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://serverlesslab.com&quot;&gt;&lt;img alt=&quot;Serverless Lab website preview&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1200&quot; height=&quot;675&quot; src=&quot;https://loige.co/_astro/serverless-lab-preview-loige-co-2017-a-year-in-review.CFI6oqEJ_Z1bnCjF.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Serverless Lab&lt;/strong&gt; is a side-project started by &lt;a href=&quot;https://twitter.com/podgeypoos79&quot;&gt;Padraig “Podge” O’Brien&lt;/a&gt; and myself to help companies to get started quickly with serverless technologies on AWS.&lt;/p&gt;
&lt;p&gt;The support is given with a day-long in-house training course that introduces all the components needed to build a wide range of applications using serverless on AWS. At the moment we defined an introductory course and an advanced one.&lt;/p&gt;
&lt;p&gt;Some of our learning materials have been open sourced and you can check them out on the &lt;a href=&quot;https://github.com/lucpod&quot;&gt;LucPod organisation on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Yes, LucPod stands for &lt;em&gt;LUCiano&lt;/em&gt; and &lt;em&gt;PODge&lt;/em&gt; (Padraig’s nickname)… I know, we have to figure out a better name 😂&lt;/p&gt;
&lt;h3 id=&quot;middy&quot;&gt;Middy&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://middy.js.org/&quot;&gt;&lt;img alt=&quot;Middy website preview&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1200&quot; height=&quot;675&quot; src=&quot;https://loige.co/_astro/middy-js-org-middleware-framework-preview-loige-co-2017-a-year-in-review.C3eZZUtT_ZRt1dq.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Middy&lt;/strong&gt; is a &lt;em&gt;Node.js middleware engine for AWS Lambda&lt;/em&gt;. It basically allows you to take care of tedious and repetitive tasks such as validation, input deserialization and output serialization by encapsulating this external logic into reusable and testable middlewares. With Middy, your lambda functions will look like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;middy&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;middy&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;middleware1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;middleware2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;middleware3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;middy/middlewares&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;originalHandler&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;callback&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/* your pure business logic */&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;handler&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;middy&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;originalHandler&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;handler&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;middleware1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;middleware2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;middleware3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#AF4238&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#AF4238&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;handler&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const middy = require(&amp;#x27;middy&amp;#x27;)const { middleware1, middleware2, middleware3 } = require(&amp;#x27;middy/middlewares&amp;#x27;)const originalHandler = (event, context, callback) =&gt; {  /* your pure business logic */}const handler = middy(originalHandler)handler  .use(middleware1())  .use(middleware2())  .use(middleware3())module.exports = { handler }&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;You can see from the example that the business logic is clearly defined in the &lt;code&gt;originalHandler&lt;/code&gt; and that the handler function doesn’t get polluted with additional code that is attached as a &lt;em&gt;decorator&lt;/em&gt; with the &lt;code&gt;use&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Middy is still a pretty young and immature project, but, it’s currently the only solution in this space (as far as I know), so it’s getting a bit of attention. I had the idea of starting this project, but since then it has been a community effort and the current team is composed by some amazing people in the Open Source space:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/acambas_sasa&quot;&gt;Aleksandar Cambas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/DavidWells&quot;&gt;David Wells&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/katavic_d&quot;&gt;Domagoj Katavic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/tech_fort&quot;&gt;Joe Minichino&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/Podgeypoos79&quot;&gt;Padraig O’brien&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/quasi_modal&quot;&gt;Peter Caulfield&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, a special mention goes to &lt;a href=&quot;https://github.com/joseSantacruz&quot;&gt;Jose Santacruz&lt;/a&gt; for bringing Typescript support into Middy.&lt;/p&gt;
&lt;p&gt;If you like this idea (and open source in general), remember to &lt;a href=&quot;https://github.com/middyjs/middy&quot;&gt;give it a star on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I hope the project will grow in 2018 and get much more stable and complete.&lt;/p&gt;
&lt;h3 id=&quot;fastify&quot;&gt;Fastify&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;Fastify website preview&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1200&quot; height=&quot;675&quot; src=&quot;https://loige.co/_astro/fastify-nodejs-web-framework-preview-loige-co-2017-a-year-in-review.4tE8WdGI_Z1EARkm.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fastify&lt;/strong&gt; is a fast and low overhead web framework for Node.js. If you like Express, you are definitely gonna love Fastify.&lt;/p&gt;
&lt;p&gt;Fastify was started by two amazing developers: &lt;a href=&quot;https://twitter.com/delvedor&quot;&gt;
Tomas Della Vedova&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/matteocollina&quot;&gt;Matteo Collina&lt;/a&gt; in an attempt to create a performant and scalable, yet very friendly web framework for Node.js.&lt;/p&gt;
&lt;p&gt;Now &lt;a href=&quot;https://github.com/orgs/fastify/people&quot;&gt;the team&lt;/a&gt; has grown up a lot and version 1.0 is very close to being released. You can surely expect big things from this framework in 2018.&lt;/p&gt;
&lt;p&gt;For what concerns me, I have been involved mostly in taking care of the &lt;a href=&quot;https://github.com/fastify/website&quot;&gt;Fastify website&lt;/a&gt; and its &lt;a href=&quot;https://circleci.com/gh/fastify/website&quot;&gt;Continuous Integration pipeline&lt;/a&gt;. I made sure that every time there’s a new release, the documentation get’s pulled from the main repository and the website is rebuilt, versioned and published. This way, contributors don’t have to worry much about the website look and feel and they just have to maintain a bunch of handy markdown files to document all the aspects of the framework. This part is built by using a bunch of tailored Node.js scripts adopting git and the GitHub APIs, &lt;a href=&quot;http://www.metalsmith.io&quot;&gt;Metalsmith&lt;/a&gt; as a static website engine, &lt;a href=&quot;https://circleci.com&quot;&gt;Circle CI&lt;/a&gt; for the CI pipeline, GitHub Pages and &lt;a href=&quot;https://www.cloudflare.com&quot;&gt;Cloudflare&lt;/a&gt; for the web hosting.&lt;/p&gt;
&lt;h2 id=&quot;blog-posts&quot;&gt;Blog posts&lt;/h2&gt;
&lt;p&gt;I have to admit this year I wasn’t a very prolific author (again 😓)… I guess all the stuff described above took almost all my free time. Anyway, I still managed to write some posts. Here are the most interesting ones (based on actual reading stats):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/using-lets-encrypt-and-certbot-to-automate-the-creation-of-certificates-for-openvpn/&quot;&gt;Using Let’s Encrypt and Certbot to automate the creation of certificates for OpenVPN&lt;/a&gt; (~3.500 views)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/unshorten-expand-short-urls-with-node-js/&quot;&gt;Unshorten (expand) short URLs with Node.js&lt;/a&gt; (~2.500 views)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/from-bare-metal-to-serverless/&quot;&gt;From bare metal to Serverless&lt;/a&gt; (~1.500 views)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/my-universal-javascript-web-applications-talk-at-codemotion-rome-2017/&quot;&gt;My Universal JavaScript Web Applications talk at Codemotion Rome 2017&lt;/a&gt; (~1.200 views)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s funny to see that most of the traffic is still driven by old (and probably outdated) articles from the previous years like &lt;a href=&quot;https://loige.co/developing-a-web-application-with-lumen-and-mysql/&quot;&gt;Developing a web application with Lumen and MySql&lt;/a&gt; (~12.000 views) and &lt;a href=&quot;https://loige.co/gulp-and-ftp-update-a-website-on-the-fly/&quot;&gt;Gulp and FTP: update a website “on the fly”&lt;/a&gt; (~5.700 views).&lt;/p&gt;
&lt;p&gt;👎 The total number of page views amounts to about 57.000 views, which compared to the previous year total of 90.000 is a dramatic decrease of 36.67%!&lt;/p&gt;
&lt;p&gt;I guess I have to write more and find more interesting topics if I want to keep this blog relevant in 2018!&lt;/p&gt;
&lt;h2 id=&quot;external-posts&quot;&gt;External posts&lt;/h2&gt;
&lt;p&gt;Aside from the articles published on my blog I had the pleasure to collaborate again with &lt;a href=&quot;https://scotch.io/&quot;&gt;Scotch.io&lt;/a&gt; and to establish a new collaboration with &lt;a href=&quot;https://www.twilio.com&quot;&gt;Twilio&lt;/a&gt; to publish 2 posts as a guest author:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://scotch.io/tutorials/create-a-custom-slack-slash-command-with-nodejs-and-express&quot;&gt;Create a custom Slack slash command with Node.js and Express&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.twilio.com/blog/2017/12/automated-sms-notifications-aws-lambda-javascript-twilio-sms-apis.html&quot;&gt;Automated SMS Notifications with AWS Lambda, JavaScript and Twilio SMS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s always fun and rewarding to write guest posts and it’s a nice way to get my name out from my common channels.&lt;/p&gt;
&lt;p&gt;I guess in 2018 I should keep doing that and maybe build some new relationship with other publishers :)&lt;/p&gt;
&lt;h2 id=&quot;open-sourcing&quot;&gt;Open Sourcing&lt;/h2&gt;
&lt;p&gt;As usual, I kept spending some time working out some small open source contributions, mostly creating little Node.js libraries or command line utilities for different purposes. Here’s the complete list of the open source contributions I made:&lt;/p&gt;
&lt;h3 id=&quot;organisations&quot;&gt;Organisations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fastify&quot;&gt;fastify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FullStackBulletin&quot;&gt;FullStackBulletin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/middyjs&quot;&gt;middy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lucpod&quot;&gt;lucpod&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;repositories&quot;&gt;Repositories&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jekyll/jekyll&quot;&gt;jekyll/jekyll&lt;/a&gt; (contribution): Jekyll is a blog-aware, static site generator in Ruby.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mattallty/Caporal.js&quot;&gt;mattallty/Caporal.js&lt;/a&gt; (contribution): A full-featured framework for building command line applications (cli) with node.js&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/anaibol/awesome-serverless&quot;&gt;anaibol/awesome-serverless&lt;/a&gt; (contribution): A curated list of awesome services, solutions and resources for serverless / nobackend applications&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/karlhorky/awesome-speakers&quot;&gt;karlhorky/awesome-speakers&lt;/a&gt; (contribution): Awesome speakers in the programming and design communities&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mdvorscak/metalsmith-browser-sync&quot;&gt;mdvorscak/metalsmith-browser-sync&lt;/a&gt; (contribution): A Metalsmith plugin to make your workflow easier&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/1000ch/node-github-markdown&quot;&gt;1000ch/node-github-markdown&lt;/a&gt; (contribution): Parse GitHub flavored markdown to static html&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/gianarb/wikidiff&quot;&gt;gianarb/wikidiff&lt;/a&gt; (contribution): A wikipedia “snapshotter”&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/judo-heroes-2&quot;&gt;lmammino/judo-heroes-2&lt;/a&gt;: Universal Javascript sample application with React Router 4 and Express 5&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/webhook-tunnel&quot;&gt;lmammino/webhook-tunnel&lt;/a&gt;: A little HTTP proxy suitable to create tunnels for webhook endpoints protected behind a firewall or a VPN&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/slack-shorturl-integration&quot;&gt;lmammino/slack-shorturl-integration&lt;/a&gt;: A slack slash command server to shorten URLs using Rebrandly API&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/terraform-openvpn&quot;&gt;lmammino/terraform-openvpn&lt;/a&gt;: A sample terraform setup for OpenVPN using Let’s Encrypt and Certbot to generate certificates&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/lambda-currency-exchange-sms&quot;&gt;lmammino/lambda-currency-exchange-sms&lt;/a&gt;: An AWS lambda function that sends you an SMS (using Twilio) with today exchange rate for a give currency pair&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/sample-jwt-webapp&quot;&gt;lmammino/sample-jwt-webapp&lt;/a&gt;: A sample JWT web app that can be use to demonstrate how to escalate permissions by cracking and forging JWT tokens&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/tall&quot;&gt;lmammino/tall&lt;/a&gt;: Promise-based, No-dependency URL unshortner (expander) module for Node.js&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/swagger-jsdoc-generator&quot;&gt;lmammino/swagger-jsdoc-generator&lt;/a&gt;: Command line script that generates a swagger file based on jsdoc comments&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/json-dynamo-putrequest&quot;&gt;lmammino/json-dynamo-putrequest&lt;/a&gt;: Converts an arbitrary JSON into a DynamoDB PutRequest JSON to simplify the import of the raw data into DynamoDB.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/simple-react-universal-demo&quot;&gt;lmammino/simple-react-universal-demo&lt;/a&gt;: A simple demo to demonstrate Universal JavaScript with React&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/heroku-buildpack-npm-build&quot;&gt;lmammino/heroku-buildpack-npm-build&lt;/a&gt;: Runs npm build on heroku&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/yaml-prune&quot;&gt;lmammino/yaml-prune&lt;/a&gt;: A simple command line script that allows to prune parts of a yaml file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;👍 Comparing last year (13) to this year (19) I had a +46.15% repo contributions increase. Another pretty good vanity metric!&lt;/p&gt;
&lt;p&gt;PS: I finally have more than 100 repositories on my GitHub account 🎉&lt;/p&gt;
&lt;h2 id=&quot;learning&quot;&gt;Learning&lt;/h2&gt;
&lt;p&gt;This year I kept familiarising know technologies such as &lt;strong&gt;AWS&lt;/strong&gt;, &lt;strong&gt;serverless&lt;/strong&gt;, &lt;strong&gt;Node.js&lt;/strong&gt;, &lt;strong&gt;React&lt;/strong&gt;, &lt;strong&gt;Docker&lt;/strong&gt; and &lt;strong&gt;python&lt;/strong&gt;, but I also gained knowledge of some interesting technologies/tools such as &lt;strong&gt;Terraform&lt;/strong&gt; and &lt;strong&gt;Ansible&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Also, I am getting more and more interested in the following technologies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rust-lang.org&quot;&gt;Rust&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kubernetes.io&quot;&gt;Kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.elastic.co&quot;&gt;Elastic Search&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;CSS &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout&quot;&gt;Grid&lt;/a&gt; &amp;#x26; &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox&quot;&gt;Flexbox&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;👎 I admit I dropped the ball on Elixir, and even though I spent a bit of time reading about &lt;a href=&quot;http://phoenixframework.org&quot;&gt;Phoenix&lt;/a&gt; (the most famous Elixir web framework), I never really built something barely interesting with it.&lt;/p&gt;
&lt;h2 id=&quot;previous-years-goals&quot;&gt;Previous years goals&lt;/h2&gt;
&lt;p&gt;Now it’s time to check whether I met &lt;a href=&quot;https://loige.co/2016-a-year-in-review#expectationsfornextyear&quot;&gt;the goals I set last year&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Keep improving my knowledge of Node.js and everything related&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;Publish the first version of my side project with Andrea&lt;/strong&gt;&lt;br&gt;
(that mysterious side project was totally dropped, but we managed to publish Fullstack Bulletin instead, so this was not a complete failure)&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Getting better with AWS and the Serverless framework&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;❌ &lt;strong&gt;Move my blog to a static publishing engine and (possibly) use a serverless hosting approach&lt;/strong&gt;&lt;br&gt;
(this is still a work in progress 😟)&lt;/li&gt;
&lt;li&gt;❌ &lt;strong&gt;Keep investing time on Elixir and build something with it&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Presentations and talks at conferences and meet-ups&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;Get more proficient with VIM&lt;/strong&gt;&lt;br&gt;
(I think I got slightly better, but VIM it’s not my primary editor still)&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Keep open sourcing stuff&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Travel more!&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;More serious and constant BJJ training!&lt;/strong&gt;&lt;br&gt;
(I finally got my blue belt, but still I feel like I am training way less then I should!)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;expectations-for-next-year&quot;&gt;Expectations for next year&lt;/h2&gt;
&lt;p&gt;Ok, it’s finally time to move to the good intentions for the next year! I have been very long already so I’ll just sort this part out with a simple unordered checklist, I am already looking forward to seeing, in one year time, how many items will be crossed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MOAR conference talks/workshops (at least 8)&lt;/li&gt;
&lt;li&gt;Write at least 8 quality blog posts (excluding this one!)&lt;/li&gt;
&lt;li&gt;Learn a lot about Security, Machine Learning and networking (😇 Vectra, please…)&lt;/li&gt;
&lt;li&gt;Keep contributing to Fastify&lt;/li&gt;
&lt;li&gt;Keep working on Middy&lt;/li&gt;
&lt;li&gt;Move my blog to a static publishing engine and (possibly) use a serverless hosting approach&lt;/li&gt;
&lt;li&gt;Learn enough about Rust and build something with it&lt;/li&gt;
&lt;li&gt;Learn enough about Elastic Search and build something with it&lt;/li&gt;
&lt;li&gt;Learn enough about Kubernetes and build something with it&lt;/li&gt;
&lt;li&gt;Do stuff with CSS Grids and Flexbox&lt;/li&gt;
&lt;li&gt;Keep learning AWS and serverless&lt;/li&gt;
&lt;li&gt;More serious and constant BJJ training!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Well, That’s all… I hope I didn’t bore you to death!
Anyway, &lt;strong&gt;I’d really love to know what was your biggest achievement in 2017&lt;/strong&gt;. If you feel like you want to share this information with me feel free to &lt;a href=&quot;https://twitter.com/loige&quot;&gt;write me on Twitter&lt;/a&gt; or to post a comment here! I’ll make sure to have (at least) a pint in your honour! 🍻&lt;/p&gt;
&lt;p&gt;Finally, I &lt;strong&gt;wish a fantastic 2018&lt;/strong&gt; to you all!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/2017-a-year-in-review.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/2017-a-year-in-review.png" width="1200" height="630"/></media:content><category>life</category><author>Luciano Mammino</author><comments>https://loige.co/2017-a-year-in-review/#comments</comments><enclosure url="https://loige.co/og/2017-a-year-in-review.png" length="0" type="image/png"/></item><item><title>AWS Command line: S3 content from stdin or to stdout</title><link>https://loige.co/aws-command-line-s3-content-from-stdin-or-to-stdout/</link><guid isPermaLink="true">https://loige.co/aws-command-line-s3-content-from-stdin-or-to-stdout/</guid><description>The AWS CLI s3 cp command supports streaming content to and from S3 using stdin/stdout with the - argument. This enables powerful pipelines without intermediary files.</description><pubDate>Sat, 05 May 2018 12:00:14 GMT</pubDate><content:encoded>&lt;p&gt;This article presents a quick tip that will help you deal with the content of files in S3 through the AWS command line in a much faster and simpler way.&lt;/p&gt;
&lt;p&gt;Did you ever want to simply print the content of a file in S3 from your command line and maybe pipe the output to another command? Or maybe, did you ever needed to pipe the standard output of a sequence of commands directly into a file in S3? I had this need multiple times and, before my amazing colleague Paul made me discover the tip I am about to describe here, I was always using intermediary files to keep track of the input and output of S3 files.&lt;/p&gt;
&lt;h2 id=&quot;some-examples&quot;&gt;Some examples&lt;/h2&gt;
&lt;p&gt;Let’s make few practical examples to make this use case easier to grasp.&lt;/p&gt;
&lt;p&gt;Imagine you have a PostgreSQL database containing GeoIP data and you want to dump all the data to a CSV, gzip it and store it an S3 bucket.&lt;/p&gt;
&lt;p&gt;This is how I used to solve this problem:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# dump the data from PostgreSQL to a compressed csv&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;psql&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-U&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-d&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;db_name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Copy (Select * From geoip_v4) To STDOUT With CSV HEADER DELIMITER &apos;,&apos;;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;gzip&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;geoip_v4_data.csv.gz&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# upload the resulting file to S3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;cp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;geoip_v4_data.csv.gz&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;s3://my-amazing-bucket/geoip_v4_data.csv.gz&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;psql -U user -d db_name -c &amp;#x22;Copy (Select * From geoip_v4) To STDOUT With CSV HEADER DELIMITER &amp;#x27;,&amp;#x27;;&amp;#x22; | gzip &gt; geoip_v4_data.csv.gzaws s3 cp geoip_v4_data.csv.gz s3://my-amazing-bucket/geoip_v4_data.csv.gz&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;At some point in the future, you probably want to read the file from S3 and search for a given CIDR in the content of the file. Again, this is how I would have solved this problem:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# download the file from S3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;cp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;s3://my-amazing-bucket/geoip_v4_data.csv.gz&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# decompress the file and search inside it&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;gunzip&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;geoip_v4_data.csv.gz&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;1.0.8.0/21&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;aws s3 cp s3://my-amazing-bucket/geoip_v4_data.csv.gz .gunzip -c geoip_v4_data.csv.gz | grep &amp;#x22;1.0.8.0/21&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In both cases, I am creating intermediary files and, as you probably already know, this is not ideal for many reasons. Just to name few, this is a slower operation (not fully stream-able), it takes extra space on disk (imagine you have to deal with very big files), finally, it also needs an extra command. Wouldn’t it be great if we could solve both problems by writing a single pipeline of commands?&lt;/p&gt;
&lt;h2 id=&quot;the-magic---option-in-aws-cp&quot;&gt;The “magic” &lt;code&gt;-&lt;/code&gt; option in &lt;code&gt;aws cp&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Buried at the very bottom of the &lt;code&gt;aws s3 cp&lt;/code&gt; command help you might (by accident) find this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Uploading a local file stream to S3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;WARNING:: PowerShell may alter the encoding of or add a CRLF  to  piped&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;input.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;The  following  cp  command  uploads  a local file stream from standard&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;input to a specified bucket and key:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;aws s3 cp - s3://mybucket/stream.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Downloading an S3 object as a local file stream&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;WARNING:: PowerShell may alter the encoding of or add a CRLF  to  piped&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;or redirected output.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;The  following cp command downloads an S3 object locally as a stream to&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;standard output. Downloading as a stream is  not  currently  compatible&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;with the --recursive parameter:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;aws s3 cp s3://mybucket/stream.txt -&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Uploading a local file stream to S3  WARNING:: PowerShell may alter the encoding of or add a CRLF  to  piped  input.  The  following  cp  command  uploads  a local file stream from standard  input to a specified bucket and key:    aws s3 cp - s3://mybucket/stream.txtDownloading an S3 object as a local file stream  WARNING:: PowerShell may alter the encoding of or add a CRLF  to  piped  or redirected output.  The  following cp command downloads an S3 object locally as a stream to  standard output. Downloading as a stream is  not  currently  compatible  with the --recursive parameter:    aws s3 cp s3://mybucket/stream.txt -&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;To make it simple, when running &lt;code&gt;aws s3 cp&lt;/code&gt; you can use the special argument &lt;code&gt;-&lt;/code&gt; to indicate the content of the standard input or the content of the standard output (depending on where you put the special argument).&lt;/p&gt;
&lt;h2 id=&quot;writing-to-s3-from-the-standard-output&quot;&gt;Writing to S3 from the standard output&lt;/h2&gt;
&lt;p&gt;Using this newly acquired piece of knowledge, we now know we can do something like this to write content from the standard output directly to a file in S3:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;hello world&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;cp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;s3://some-bucket/hello.txt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;echo &amp;#x22;hello world&amp;#x22; | aws s3 cp - s3://some-bucket/hello.txt&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This way we can rewrite the solution to our first problem as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;psql&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-U&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-d&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;db_name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Copy (Select * From geoip_v4) To STDOUT With CSV HEADER DELIMITER &apos;,&apos;;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;gzip&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;cp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;s3://my-amazing-bucket/geoip_v4_data.csv.gz&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;psql -U user -d db_name -c &amp;#x22;Copy (Select * From geoip_v4) To STDOUT With CSV HEADER DELIMITER &amp;#x27;,&amp;#x27;;&amp;#x22; | gzip | aws s3 cp - s3://my-amazing-bucket/geoip_v4_data.csv.gz&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This time no intermediary file is created and the data from the gzipped file is immediately streamed to S3 as soon as the first bytes start to be available.&lt;/p&gt;
&lt;h2 id=&quot;using-data-from-s3-as-input-for-other-commands&quot;&gt;Using data from S3 as input for other commands&lt;/h2&gt;
&lt;p&gt;The magic &lt;code&gt;-&lt;/code&gt; argument can be used also to read the content of files in s3 and pass it in the standard output, for instance, you could do the following:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;cp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;s3://some-bucket/hello.txt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;-&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;aws s3 cp s3://some-bucket/hello.txt -&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This will output:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;hello world&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;hello world&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Let’s use this option to rewrite the solution to our second problem as a one-liner:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;cp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;s3://my-amazing-bucket/geoip_v4_data.csv.gz&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;gunzip&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;geoip_v4_data.csv.gz&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;grep&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;1.0.8.0/21&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;aws s3 cp s3://my-amazing-bucket/geoip_v4_data.csv.gz - | gunzip -c geoip_v4_data.csv.gz | grep &amp;#x22;1.0.8.0/21&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This approach looks much similar to what you would do with a local file and makes integrating other commands seamless with the content of files available in your S3 storage.&lt;/p&gt;
&lt;h2 id=&quot;pipeline-processing-of-s3-files&quot;&gt;Pipeline processing of S3 files&lt;/h2&gt;
&lt;p&gt;We can combine the learnings from the previous two sections to build processing pipelines for S3 files.&lt;/p&gt;
&lt;p&gt;Just to give you a practical example, imagine you have to optimize a png image available in an S3 bucket and save the resulting image in a new bucket.&lt;/p&gt;
&lt;p&gt;To optimize an image we can use &lt;a href=&quot;https://github.com/imagemin/imagemin-cli&quot;&gt;&lt;code&gt;imagemin&lt;/code&gt;&lt;/a&gt; which accepts an image in the standard input and returns the optimized image content through the standard output.&lt;/p&gt;
&lt;p&gt;Assuming we have our source image in &lt;code&gt;s3://my-images/image.png&lt;/code&gt; and we want to save the optimized version in &lt;code&gt;s3://my-images-optimized/image.png&lt;/code&gt;, we can write the pipeline as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;cp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;s3://my-images/image.png&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;imagemin&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;cp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;s3://my-images-optimized/image.png&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;aws s3 cp s3://my-images/image.png - | imagemin | aws s3 cp - s3://my-images-optimized/image.png&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;What will happen behind the scene with this pipeline of commands is the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;S3 will start to stream the binary content of &lt;code&gt;s3://my-images/image.png&lt;/code&gt; to the standard output&lt;/li&gt;
&lt;li&gt;The standard output is then piped to &lt;code&gt;imagemin&lt;/code&gt; and used as input stream&lt;/li&gt;
&lt;li&gt;&lt;code&gt;imagemin&lt;/code&gt; will start immediately to process the stream and produce an output stream representing the optimized image&lt;/li&gt;
&lt;li&gt;This output stream is then piped to the AWS CLI again and the &lt;code&gt;s3 cp&lt;/code&gt; command will start to write it to the destination bucket.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;No intermediary file is created in the executing machine and the content is just kept in memory in a streaming fashion during the different phases of the pipeline.&lt;/p&gt;
&lt;h2 id=&quot;the-5gb-caveat&quot;&gt;The 5GB caveat&lt;/h2&gt;
&lt;p&gt;If you are writing to S3 files that are bigger than 5GB, you have to use the &lt;code&gt;--expected-size&lt;/code&gt; option so that AWS CLI can calculate the proper number of parts in the multi-part upload. If you don’t do this you’ll exceed the number of parts allowed in a multi-part upload and your request will fail.&lt;/p&gt;
&lt;p&gt;From the &lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/reference/s3/cp.html&quot;&gt;AWS CLI Documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;--expected-size&lt;/code&gt; (string): This argument specifies the expected size of a stream in terms of bytes. Note that this argument is needed only when a stream is being uploaded to s3 and the size is larger than 5GB. Failure to include this argument under these conditions may result in a failed upload due to too many parts in the upload.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;--expected-size&lt;/code&gt; should be equal or greater than the size of the upload and it doesn’t have to be perfect. Just close enough.&lt;/p&gt;
&lt;p&gt;(Thanks to mahinka for this suggestion)&lt;/p&gt;
&lt;h2 id=&quot;thats-all-folks&quot;&gt;That’s all folks&lt;/h2&gt;
&lt;p&gt;I hope this little trick is going be useful to you and that it will allow you to use S3 in a much similar way to how you would use a local file system.&lt;/p&gt;
&lt;p&gt;I am really curious to know what kind of use cases you might come up with, so please, let me know in the comments here if you’ll ever use the nifty &lt;code&gt;-&lt;/code&gt; option in the &lt;code&gt;aws s3 cp&lt;/code&gt; command line utility.&lt;/p&gt;
&lt;p&gt;I really look forward to hearing from you!&lt;/p&gt;
&lt;p&gt;Special thanks to Paul for making me discover this trick and to &lt;a href=&quot;https://www.reddit.com/user/mahinka&quot;&gt;mahinka&lt;/a&gt; and &lt;a href=&quot;https://www.reddit.com/user/paul345&quot;&gt;paul345&lt;/a&gt; (on &lt;a href=&quot;https://www.reddit.com/r/aws/comments/8h73uf/aws_command_line_s3_content_from_stdin_or_to/&quot;&gt;Reddit&lt;/a&gt;) for corrections and suggestions.&lt;/p&gt;
&lt;p&gt;Until next time, ciao! 👋&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/aws-command-line-s3-content-from-stdin-or-to-stdout.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/aws-command-line-s3-content-from-stdin-or-to-stdout.png" width="1200" height="630"/></media:content><category>aws</category><category>bash</category><category>shell</category><author>Luciano Mammino</author><comments>https://loige.co/aws-command-line-s3-content-from-stdin-or-to-stdout/#comments</comments><enclosure url="https://loige.co/og/aws-command-line-s3-content-from-stdin-or-to-stdout.png" length="0" type="image/png"/></item><item><title>Using Let’s Encrypt and Certbot to automate the creation of certificates for OpenVPN</title><link>https://loige.co/using-lets-encrypt-and-certbot-to-automate-the-creation-of-certificates-for-openvpn/</link><guid isPermaLink="true">https://loige.co/using-lets-encrypt-and-certbot-to-automate-the-creation-of-certificates-for-openvpn/</guid><description>This post explains how to use Let&apos;s Encrypt and Certbot to automatically generate and renew SSL certificates for OpenVPN. It provides a complete Terraform setup as a practical example.</description><pubDate>Mon, 19 Jun 2017 22:00:20 GMT</pubDate><content:encoded>&lt;p&gt;Recently at &lt;a href=&quot;https://planet9energy.com&quot;&gt;Planet 9 Energy&lt;/a&gt;, I had to setup a VPN access to secure some of our internal services. One of the requirements was to make the provisioning easy to reproduce over multiple environments, so we ended up playing a bit with Terraform, while obviously adopting OpenVPN for the VPN server.&lt;/p&gt;
&lt;p&gt;Another important requirement was to expose the OpenVPN web interface (also called Access Server) using an SSL, which I was expecting to be one of the most challenging things to automate, instead, it turned out to be very easy using &lt;a href=&quot;https://letsencrypt.org&quot;&gt;Let’s Encrypt&lt;/a&gt; and &lt;a href=&quot;https://certbot.eff.org&quot;&gt;Certbot&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In this article, I will illustrate you how to use Certbot to automate the creation of SSL certificates (for OpenVPN as a practical example) and how to integrate this process in AWS-land using Terraform.&lt;/p&gt;
&lt;h2 id=&quot;installing-certbot&quot;&gt;Installing Certbot&lt;/h2&gt;
&lt;p&gt;Installing Certbot on a Ubuntu (Xenial) machine is as easy as:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;apt-get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-y&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;software-properties-common&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;add-apt-repository&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-y&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;ppa:certbot/certbot&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;apt-get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-y&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;update&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;apt-get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-y&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;certbot&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sudo apt-get -y install software-properties-commonsudo add-apt-repository -y ppa:certbot/certbotsudo apt-get -y updatesudo apt-get -y install certbot&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This code uses the &lt;code&gt;certbot&lt;/code&gt; PPA to install the executable.&lt;/p&gt;
&lt;p&gt;A Little tip (in case you don’t know it yet): &lt;code&gt;-y&lt;/code&gt; allows the install to be non-interactive and to proceed without the need to confirm every operation from the keyboard.&lt;/p&gt;
&lt;p&gt;From this moment on you can use the &lt;code&gt;certbot&lt;/code&gt; executable.&lt;/p&gt;
&lt;p&gt;If you want to have an idea of its capabilities you can simply run:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;certbot&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--help&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;certbot --help&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The outcome will be something like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Certbot help output&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;575&quot; height=&quot;764&quot; src=&quot;https://loige.co/_astro/certbot-help-output-ubuntu.CRUrmSok_16fTFA.webp&quot; &gt;&lt;/p&gt;
&lt;h2 id=&quot;generating-a-certificate-with-certbot&quot;&gt;Generating a certificate with Certbot&lt;/h2&gt;
&lt;p&gt;Certbot uses Let’s Encrypt to generate a certificate. Let’s encrypt issues a certificate for your domain only if able to verify that you really own that domain and that it is associated with the public IP of the machine from which you are running certbot.&lt;/p&gt;
&lt;p&gt;So, in order to pass the verification process, you need to have a web server running on your machine and accessible from the outside world. While Certbot supports the main web servers such as &lt;a href=&quot;/tag/nginx/&quot;&gt;Nginx&lt;/a&gt; and Apache, it also features a standalone server that you can use exclusively for the verification process. This web server will run on the standard web ports (80 and 443), so if you have other services using these ports you need to stop them first.&lt;/p&gt;
&lt;p&gt;In the case of OpenVPN you can stop its web server with:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;service&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;openvpnas&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;stop&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sudo service openvpnas stop&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Then you can run certbot command line with the following options:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;certbot&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;certonly&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--standalone&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--non-interactive&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--agree-tos&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--email&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;YOUR_CERTIFICATE_EMAIL&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--domains&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;YOUR_DOMAIN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--pre-hook&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;sudo service openvpnas stop&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--post-hook&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;sudo service openvpnas start&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sudo certbot certonly \  --standalone \  --non-interactive \  --agree-tos \  --email YOUR_CERTIFICATE_EMAIL \  --domains YOUR_DOMAIN \  --pre-hook &amp;#x27;sudo service openvpnas stop&amp;#x27; \  --post-hook &amp;#x27;sudo service openvpnas start&amp;#x27;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Let’s see briefly what every option is doing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--standalone&lt;/code&gt;: runs the standalone web server for the verification process.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--non-interactive&lt;/code&gt;: runs in totally automated mode, never asks for input.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--agree-tos&lt;/code&gt;: needed to make the above work, with this parameter you are confirming you agree to the terms of service.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--email&lt;/code&gt;: the certificate email.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--domains&lt;/code&gt;: the certificate domain.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--pre-hook&lt;/code&gt;: this is needed for the auto-renewal of the certificate and describes what is the command to run before the renewal process can be executed. We are using it to stop the OpenVPN web interface.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--post-hook&lt;/code&gt;: similar to the previous one, allows us to specify a command to be executed after a certificate is renewed, we use it to restart the OpenVPN web interface.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This command generates numerous files including &lt;code&gt;server.crt&lt;/code&gt; and &lt;code&gt;server.key&lt;/code&gt;, the two files we need to use in OpenVPN. So let’s link them into the proper OpenVPN folder:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/etc/letsencrypt/live/YOUR_DOMAIN/cert.pem&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/usr/local/openvpn_as/etc/web-ssl/server.crt&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/etc/letsencrypt/live/YOUR_DOMAIN/privkey.pem&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/usr/local/openvpn_as/etc/web-ssl/server.key&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sudo ln -s -f /etc/letsencrypt/live/YOUR_DOMAIN/cert.pem /usr/local/openvpn_as/etc/web-ssl/server.crtsudo ln -s -f /etc/letsencrypt/live/YOUR_DOMAIN/privkey.pem /usr/local/openvpn_as/etc/web-ssl/server.key&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We link them because they will be changed in the future by the renewal process, so we are sure that OpenVPN will be always using the most updated certificate files.&lt;/p&gt;
&lt;p&gt;And, finally, we can restart OpenVPN:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;service&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;openvpnas&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;start&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sudo service openvpnas start&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;After few seconds your OpenVPN website should be up and running, and with a shiny green icon indicating that the website is properly encrypted through a signed certificate, woohoo, well done!&lt;/p&gt;
&lt;h2 id=&quot;a-complete-example-infrastructure-with-terraform&quot;&gt;A complete example infrastructure with Terraform&lt;/h2&gt;
&lt;p&gt;I am happy to share with you a simplified version of my Terraform OpenVPN project, to give you an example of how you can use the aforementioned details in a Terraform context.&lt;/p&gt;
&lt;p&gt;All the code available in the following section is also available as a &lt;a href=&quot;https://github.com/lmammino/terraform-openvpn&quot;&gt;repository on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let’s start with a list of the AWS resources we need in order to provision a fully functional OpenVPN:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;VPC&lt;/strong&gt; (Virtual Private Cloud)&lt;/li&gt;
&lt;li&gt;One or more &lt;strong&gt;subnets&lt;/strong&gt; in the VPC&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;EC2 instance&lt;/strong&gt; to host OpenVPN&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;key pair&lt;/strong&gt; to be able to SSH into the OpenVPN machine (for maintenance or troubleshooting)&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;security group&lt;/strong&gt; (to enable traffic inside and outside the EC2 instance)&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;DNS record&lt;/strong&gt; in Route53 to expose our VPN in a subdomain&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Quite a few things to be honest, but the declarative nature of Terraform will make things easy.&lt;/p&gt;
&lt;p&gt;Let’s create a file called &lt;code&gt;openvpn.tf&lt;/code&gt; and let’s start to add things there:&lt;/p&gt;
&lt;h3 id=&quot;vpc--subnet&quot;&gt;VPC &amp;#x26; Subnet&lt;/h3&gt;
&lt;p&gt;Let’s create the VPC and the subnet:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;vpc_cidr_block&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;default &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;10.0.0.0/16&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;subnet_cidr_block&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;default &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;10.0.0.0/16&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;aws_vpc&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;cidr_block &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;vpc_cidr_block&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;aws_subnet&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;vpn_subnet&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;vpc_id     &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;aws_vpc&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;cidr_block &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;subnet_cidr_block&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;variable &amp;#x22;vpc_cidr_block&amp;#x22; {  default = &amp;#x22;10.0.0.0/16&amp;#x22;}variable &amp;#x22;subnet_cidr_block&amp;#x22; {  default = &amp;#x22;10.0.0.0/16&amp;#x22;}resource &amp;#x22;aws_vpc&amp;#x22; &amp;#x22;main&amp;#x22; {  cidr_block = &amp;#x22;${var.vpc_cidr_block}&amp;#x22;}resource &amp;#x22;aws_subnet&amp;#x22; &amp;#x22;vpn_subnet&amp;#x22; {  vpc_id     = &amp;#x22;${aws_vpc.main.id}&amp;#x22;  cidr_block = &amp;#x22;${var.subnet_cidr_block}&amp;#x22;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Here we are using two variables &lt;code&gt;vpc_cidr_block&lt;/code&gt; and &lt;code&gt;subnet_cidr_block&lt;/code&gt; that can be easily reassigned from the outside to change the configuration if needed. By default, we are creating a VPC on the &lt;code&gt;10.0.0.0/16&lt;/code&gt; IP range and a subnet spawning over the full VPN (same IP range).&lt;/p&gt;
&lt;p&gt;The rest of the code describing the VPC and the Subnet resources should be pretty self-explanatory.&lt;/p&gt;
&lt;h3 id=&quot;the-key-pair&quot;&gt;The key pair&lt;/h3&gt;
&lt;p&gt;Let’s create now the SSH key that we can use later in case we want to SSH into the OpenVPN machine.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;public_key&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;aws_key_pair&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;openvpn&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;key_name   &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;openvpn-key&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;public_key &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;public_key&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;variable &amp;#x22;public_key&amp;#x22; {}resource &amp;#x22;aws_key_pair&amp;#x22; &amp;#x22;openvpn&amp;#x22; {  key_name   = &amp;#x22;openvpn-key&amp;#x22;  public_key = &amp;#x22;${var.public_key}&amp;#x22;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Basically we are only defining here a &lt;code&gt;aws_key_pair&lt;/code&gt; resource and specifying a name and the public key.&lt;/p&gt;
&lt;p&gt;Public key is a string that comes from the variable &lt;code&gt;public_key&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Most of the time you will be creating a dedicated key with the following command:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;ssh-keygen&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;openvpn.key&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;ssh-keygen -f openvpn.key&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;this will create &lt;code&gt;openvpn.key&lt;/code&gt; (private key) and &lt;code&gt;openvpn.key.pub&lt;/code&gt; (public key). The first one is the one we would reference here.&lt;/p&gt;
&lt;p&gt;If we want to reference the content of a file we can use &lt;code&gt;&quot;${file(&quot;openvpn.key.pub&quot;)}&quot;&lt;/code&gt; to assign a terraform variable.&lt;/p&gt;
&lt;h3 id=&quot;security-group&quot;&gt;Security group&lt;/h3&gt;
&lt;p&gt;Let’s create our security group:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;ssh_port&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;default &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;22&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;ssh_cidr&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;default &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;0.0.0.0/0&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;https_port&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;default &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;443&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;https_cidr&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;default &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;0.0.0.0/0&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;tcp_port&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;default &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;943&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;tcp_cidr&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;default &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;0.0.0.0/0&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;udp_port&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;default &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1194&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;udp_cidr&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;default &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;0.0.0.0/0&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;aws_security_group&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;openvpn&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;name        &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;openvpn_sg&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;description &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Allow traffic needed by openvpn&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;vpc_id      &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;aws_vpc&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ssh&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;ingress&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;from_port   &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ssh_port&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;to_port     &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ssh_port&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;protocol    &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;tcp&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;cidr_blocks &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ssh_cidr&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// https&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;ingress&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;from_port   &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;https_port&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;to_port     &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;https_port&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;protocol    &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;tcp&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;cidr_blocks &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;https_cidr&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// open vpn tcp&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;ingress&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;from_port   &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;tcp_port&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;to_port     &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;tcp_port&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;protocol    &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;tcp&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;cidr_blocks &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;tcp_cidr&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// open vpn udp&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;ingress&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;from_port   &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;udp_port&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;to_port     &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;udp_port&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;protocol    &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;udp&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;cidr_blocks &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;udp_cidr&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// all outbound traffic&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;egress&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;from_port   &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;to_port     &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;protocol    &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;-1&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;cidr_blocks &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;0.0.0.0/0&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;variable &amp;#x22;ssh_port&amp;#x22; {  default = 22}variable &amp;#x22;ssh_cidr&amp;#x22; {  default = &amp;#x22;0.0.0.0/0&amp;#x22;}variable &amp;#x22;https_port&amp;#x22; {  default = 443}variable &amp;#x22;https_cidr&amp;#x22; {  default = &amp;#x22;0.0.0.0/0&amp;#x22;}variable &amp;#x22;tcp_port&amp;#x22; {  default = 943}variable &amp;#x22;tcp_cidr&amp;#x22; {  default = &amp;#x22;0.0.0.0/0&amp;#x22;}variable &amp;#x22;udp_port&amp;#x22; {  default = 1194}variable &amp;#x22;udp_cidr&amp;#x22; {  default = &amp;#x22;0.0.0.0/0&amp;#x22;}resource &amp;#x22;aws_security_group&amp;#x22; &amp;#x22;openvpn&amp;#x22; {  name        = &amp;#x22;openvpn_sg&amp;#x22;  description = &amp;#x22;Allow traffic needed by openvpn&amp;#x22;  vpc_id      = &amp;#x22;${aws_vpc.main.id}&amp;#x22;  // ssh  ingress {    from_port   = &amp;#x22;${var.ssh_port}&amp;#x22;    to_port     = &amp;#x22;${var.ssh_port}&amp;#x22;    protocol    = &amp;#x22;tcp&amp;#x22;    cidr_blocks = [&amp;#x22;${var.ssh_cidr}&amp;#x22;]  }  // https  ingress {    from_port   = &amp;#x22;${var.https_port}&amp;#x22;    to_port     = &amp;#x22;${var.https_port}&amp;#x22;    protocol    = &amp;#x22;tcp&amp;#x22;    cidr_blocks = [&amp;#x22;${var.https_cidr}&amp;#x22;]  }  // open vpn tcp  ingress {    from_port   = &amp;#x22;${var.tcp_port}&amp;#x22;    to_port     = &amp;#x22;${var.tcp_port}&amp;#x22;    protocol    = &amp;#x22;tcp&amp;#x22;    cidr_blocks = [&amp;#x22;${var.tcp_cidr}&amp;#x22;]  }  // open vpn udp  ingress {    from_port   = &amp;#x22;${var.udp_port}&amp;#x22;    to_port     = &amp;#x22;${var.udp_port}&amp;#x22;    protocol    = &amp;#x22;udp&amp;#x22;    cidr_blocks = [&amp;#x22;${var.udp_cidr}&amp;#x22;]  }  // all outbound traffic  egress {    from_port   = 0    to_port     = 0    protocol    = &amp;#x22;-1&amp;#x22;    cidr_blocks = [&amp;#x22;0.0.0.0/0&amp;#x22;]  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;By default, this Security group allows access from every IP address using the ports 22 (SSH), 433 (HTTPS) and all outside traffic. It also enables the traffic needed for the OpenVPN protocol both on TCP (port 943) and UDP (port 1194).
In case you want a custom setup, you can redefine all the relevant variables here (but in that case you might need to customise also the OpenVPN settings, a step which is not covered in this article).&lt;/p&gt;
&lt;h3 id=&quot;subdomain&quot;&gt;Subdomain&lt;/h3&gt;
&lt;p&gt;Let’s now create the subdomain from where our VPN will be accessible.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;route53_zone_name&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;subdomain_name&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;subdomain_ttl&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;default &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;60&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;aws_route53_zone&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;name &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;route53_zone_name&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;aws_route53_record&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;vpn&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;zone_id &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;aws_route53_zone&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;zone_id&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;name    &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;subdomain_name&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;type    &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;A&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ttl     &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;subdomain_ttl&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;records &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;aws_instance&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;openvpn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;public_ip&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;variable &amp;#x22;route53_zone_name&amp;#x22; {}variable &amp;#x22;subdomain_name&amp;#x22; {}variable &amp;#x22;subdomain_ttl&amp;#x22; {  default = &amp;#x22;60&amp;#x22;}data &amp;#x22;aws_route53_zone&amp;#x22; &amp;#x22;main&amp;#x22; {  name = &amp;#x22;${var.route53_zone_name}&amp;#x22;}resource &amp;#x22;aws_route53_record&amp;#x22; &amp;#x22;vpn&amp;#x22; {  zone_id = &amp;#x22;${data.aws_route53_zone.main.zone_id}&amp;#x22;  name    = &amp;#x22;${var.subdomain_name}&amp;#x22;  type    = &amp;#x22;A&amp;#x22;  ttl     = &amp;#x22;${var.subdomain_ttl}&amp;#x22;  records = [&amp;#x22;${aws_instance.openvpn.public_ip}&amp;#x22;]}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In this part of the code, we are defining 3 variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;route53_zone_name&lt;/code&gt;: the name of your main domain zone (e.g. “example.com.”, notice the dot at the end).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;subdomain_name&lt;/code&gt;: the name of the subdomain to use for the VPN (e.g. “vpn.example.com”).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;subdomain_ttl&lt;/code&gt;: the TTL for the domain (60 seconds by default).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then, we create a reference to the Route53 zone using the &lt;code&gt;data&lt;/code&gt; syntax.&lt;/p&gt;
&lt;p&gt;Finally, we create the record in the zone using an &lt;code&gt;aws_route53_record&lt;/code&gt; resource.&lt;/p&gt;
&lt;p&gt;Notice that we are referencing here the EC2 instance public IP, which we haven’t defined yet.&lt;/p&gt;
&lt;h3 id=&quot;ec2-instance&quot;&gt;EC2 instance&lt;/h3&gt;
&lt;p&gt;Let’s see now how we can define the EC2 instance that will host the OpenVPN software for our virtual private cloud:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;ami&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;default &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;ami-f53d7386&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ubuntu xenial openvpn ami in eu-west-1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;instance_type&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;default &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;t2.medium&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;admin_user&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;default &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;openvpn&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;admin_password&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;default &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;openvpn&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;aws_instance&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;openvpn&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;tags&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Name &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;openvpn&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ami                         &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ami&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;instance_type               &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;instance_type&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;key_name                    &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;aws_key_pair&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;openvpn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;key_name&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;subnet_id                   &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;aws_subnet&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;vpn_subnet&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;vpc_security_group_ids      &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;aws_security_group&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;openvpn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;associate_public_ip_address &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# `admin_user` and `admin_pw` need to be passed in to the appliance through `user_data`, see docs --&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# https://docs.openvpn.net/how-to-tutorialsguides/virtual-platforms/amazon-ec2-appliance-ami-quick-start-guide/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;user_data &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;USERDATA&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;admin_user=&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;admin_user&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;admin_pw=&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;admin_password&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;USERDATA&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;variable &amp;#x22;ami&amp;#x22; {  default = &amp;#x22;ami-f53d7386&amp;#x22; // ubuntu xenial openvpn ami in eu-west-1}variable &amp;#x22;instance_type&amp;#x22; {  default = &amp;#x22;t2.medium&amp;#x22;}variable &amp;#x22;admin_user&amp;#x22; {  default = &amp;#x22;openvpn&amp;#x22;}variable &amp;#x22;admin_password&amp;#x22; {  default = &amp;#x22;openvpn&amp;#x22;}resource &amp;#x22;aws_instance&amp;#x22; &amp;#x22;openvpn&amp;#x22; {  tags {    Name = &amp;#x22;openvpn&amp;#x22;  }  ami                         = &amp;#x22;${var.ami}&amp;#x22;  instance_type               = &amp;#x22;${var.instance_type}&amp;#x22;  key_name                    = &amp;#x22;${aws_key_pair.openvpn.key_name}&amp;#x22;  subnet_id                   = &amp;#x22;${aws_subnet.vpn_subnet.id}&amp;#x22;  vpc_security_group_ids      = [&amp;#x22;${aws_security_group.openvpn.id}&amp;#x22;]  associate_public_ip_address = true  # &amp;#x60;admin_user&amp;#x60; and &amp;#x60;admin_pw&amp;#x60; need to be passed in to the appliance through &amp;#x60;user_data&amp;#x60;, see docs --&gt;  # https://docs.openvpn.net/how-to-tutorialsguides/virtual-platforms/amazon-ec2-appliance-ami-quick-start-guide/  user_data = &lt;&lt;USERDATAadmin_user=${var.admin_user}admin_pw=${var.admin_password}USERDATA}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In this piece of code we are defining some variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ami&lt;/code&gt;: the id of the AMI (Amazon Machine Image) to use to run the EC2 instance. The default one is a Ubuntu Xenial OpenVPN machine that runs on the eu-west-1 region (Ireland). Feel free to &lt;a href=&quot;https://cloud-images.ubuntu.com/locator/ec2/&quot;&gt;select another image&lt;/a&gt; that might suit your needs best.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;instance_type&lt;/code&gt;: the type of instance. You can check the &lt;a href=&quot;https://aws.amazon.com/ec2/instance-types/&quot;&gt;list of all the type of EC2 instances&lt;/a&gt; to understand which one might be the best for you. The default here is ok for most of the use cases.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;admin_user&lt;/code&gt;, &lt;code&gt;admin_password&lt;/code&gt;: The username and password of the admin user for your VPN.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whit all those variable in place, we can describe a &lt;code&gt;aws_instance&lt;/code&gt; resource. Notice that we are defining it so that it will be bootstrapped in our VPC and in the subnet we specified before. Also notice that we are setting &lt;code&gt;associate_public_ip_address&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;, this way the machine will get a public IP (the one we will associate to the subdomain defined earlier).&lt;/p&gt;
&lt;p&gt;Finally we define a &lt;code&gt;user_data&lt;/code&gt; property. &lt;a href=&quot;http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html#instancedata-add-user-data&quot;&gt;EC2 User Data&lt;/a&gt; allows to provide extra configuration code that is executed as soon as the machine is bootstrapped. It is generally used to install extra software, start some service or edit configuration values. In our case, since our image already contains OpenVPN, we use it only to provide the credentials for the default OpenVPN admin user.&lt;/p&gt;
&lt;h3 id=&quot;trigger-based-provisioning-with-null_resource&quot;&gt;Trigger-based provisioning with &lt;code&gt;null_resource&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;At this point we created all the resources we need and the OpenVPN admin can be already accessed by pointing the browser to your custom subdomain (using the HTTPS protocol).&lt;/p&gt;
&lt;p&gt;If you try to do that though, you will get a warning page saying that the certificate for this domain is not valid. This is because OpenVPN is using an auto-generated self-signed certificate which is not bound to your domain, neither signed by a trusted authority (such as Let’s Encrypt).&lt;/p&gt;
&lt;p&gt;So let’s do the interesting bit here, adding a Let’s Encrypt certificate for our subdomain!&lt;/p&gt;
&lt;p&gt;If you got the basics of Terraform and AWS here you might think that we can do this by simply adding few lines to our EC2 User Data script. While this, in theory, is not wrong, is not going to work in this case because of the way our resources here depend on each other. Let’s clarify exactly why…&lt;/p&gt;
&lt;p&gt;So in our current situation, we have to respect the following order of creating resources:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a VPC&lt;/li&gt;
&lt;li&gt;Create a Subnet in the VPC&lt;/li&gt;
&lt;li&gt;Create a key pair and a security group&lt;/li&gt;
&lt;li&gt;Create an EC2 instance&lt;/li&gt;
&lt;li&gt;Create a subdomain record pointing to the public address of the EC2 instance&lt;/li&gt;
&lt;li&gt;(TODO) Create the certificate and install into the current OpenVPN instance&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So, the subdomain record can be created only after the EC2 instance is running and it has got a public IP address, only then we have a valid domain that we can use for the certificate. This means we cannot use the EC2 provisioning step, but we need to have a “trigger” that tells us when the subdomain is available and do some extra stuff.&lt;/p&gt;
&lt;p&gt;Terraform is smart enough to reconstruct the dependency graph of all our resources and to create the resources in the right order, so we don’t need to worry about that and we can keep loving the declarative style of its syntax.&lt;/p&gt;
&lt;p&gt;This means that the only thing left to do is to specify this trigger, which we can do by using a &lt;a href=&quot;https://www.terraform.io/docs/provisioners/null_resource.html&quot;&gt;&lt;code&gt;null_resource&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Quoting the official documentation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;null_resource&lt;/code&gt; is a resource that allows you to configure provisioners that are not directly associated with a single existing resource.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let’s jump straight into the code, which I believe will make everything clear:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;certificate_email&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;null_resource&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;provision_openvpn&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;triggers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;subdomain_id &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;aws_route53_record&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;vpn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;connection&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;type        &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;ssh&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;host        &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;aws_instance&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;openvpn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;public_ip&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;user        &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ssh_user&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;private_key &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;private_key&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;agent       &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;false&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;provisioner&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;remote-exec&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;inline &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;sudo apt-get install -y curl vim libltdl7 python3 python3-pip python software-properties-common unattended-upgrades&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;sudo add-apt-repository -y ppa:certbot/certbot&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;sudo apt-get -y update&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;sudo apt-get -y install python-certbot certbot&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;sudo service openvpnas stop&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;sudo certbot certonly --standalone --non-interactive --agree-tos --email &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;certificate_email&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt; --domains &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;subdomain_name&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt; --pre-hook &apos;service openvpnas stop&apos; --post-hook &apos;service openvpnas start&apos;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;sudo ln -s -f /etc/letsencrypt/live/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;subdomain_name&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/cert.pem /usr/local/openvpn_as/etc/web-ssl/server.crt&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;sudo ln -s -f /etc/letsencrypt/live/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;subdomain_name&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/privkey.pem /usr/local/openvpn_as/etc/web-ssl/server.key&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;sudo service openvpnas start&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;variable &amp;#x22;certificate_email&amp;#x22; {}resource &amp;#x22;null_resource&amp;#x22; &amp;#x22;provision_openvpn&amp;#x22; {  triggers {    subdomain_id = &amp;#x22;${aws_route53_record.vpn.id}&amp;#x22;  }  connection {    type        = &amp;#x22;ssh&amp;#x22;    host        = &amp;#x22;${aws_instance.openvpn.public_ip}&amp;#x22;    user        = &amp;#x22;${var.ssh_user}&amp;#x22;    private_key = &amp;#x22;${var.private_key}&amp;#x22;    agent       = false  }  provisioner &amp;#x22;remote-exec&amp;#x22; {    inline = [      &amp;#x22;sudo apt-get install -y curl vim libltdl7 python3 python3-pip python software-properties-common unattended-upgrades&amp;#x22;,      &amp;#x22;sudo add-apt-repository -y ppa:certbot/certbot&amp;#x22;,      &amp;#x22;sudo apt-get -y update&amp;#x22;,      &amp;#x22;sudo apt-get -y install python-certbot certbot&amp;#x22;,      &amp;#x22;sudo service openvpnas stop&amp;#x22;,      &amp;#x22;sudo certbot certonly --standalone --non-interactive --agree-tos --email ${var.certificate_email} --domains ${var.subdomain_name} --pre-hook &amp;#x27;service openvpnas stop&amp;#x27; --post-hook &amp;#x27;service openvpnas start&amp;#x27;&amp;#x22;,      &amp;#x22;sudo ln -s -f /etc/letsencrypt/live/${var.subdomain_name}/cert.pem /usr/local/openvpn_as/etc/web-ssl/server.crt&amp;#x22;,      &amp;#x22;sudo ln -s -f /etc/letsencrypt/live/${var.subdomain_name}/privkey.pem /usr/local/openvpn_as/etc/web-ssl/server.key&amp;#x22;,      &amp;#x22;sudo service openvpnas start&amp;#x22;,    ]  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;As you can see at the very top of this snippet of code, we are declaring a &lt;code&gt;null_resource&lt;/code&gt; that is triggered when the value &lt;code&gt;aws_route53_record.vpn.id&lt;/code&gt; changes, which happens when the subdomain is created. When this happens, Terraform will execute the provisioning logic defined in the rest of the code here, which essentially describes to Terraform how to connect to the OpenVPN machine and what code needs to be run and which we already discussed in the first part of this article.&lt;/p&gt;
&lt;h3 id=&quot;the-provider-configuration-and-the-variable-file&quot;&gt;The provider configuration and the variable file&lt;/h3&gt;
&lt;p&gt;Ok, our setup is almost ready… The only two things we have left to do are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;define the needed configuration to connect to our AWS account;&lt;/li&gt;
&lt;li&gt;define some values for our configuration before we can run Terraform.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To define the AWS config we need to specify the following terraform code (I generally do that into a dedicated file called &lt;code&gt;provider.tf&lt;/code&gt;, but you can write this in any terraform file in your project):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;aws_profile_name&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;variable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;aws_region&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;provider&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#AF4238&quot;&gt;&quot;aws&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;profile &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;aws_profile_name&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;region  &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;aws_region&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;variable &amp;#x22;aws_profile_name&amp;#x22; {}variable &amp;#x22;aws_region&amp;#x22; {}provider &amp;#x22;aws&amp;#x22; {  profile = &amp;#x22;${var.aws_profile_name}&amp;#x22;  region  = &amp;#x22;${var.aws_region}&amp;#x22;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Finally we can define the values for our variables. To do so we need to create a file called &lt;code&gt;terraform.tfvars&lt;/code&gt; which contains a simple list of key-value pairs:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;aws_profile_name &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;aws_region &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;eu-west-1&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;public_key &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;file&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;(&quot;key.pub&quot;)&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;private_key &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;file&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;(&quot;key&quot;)&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;certificate_email &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;tech@example.com&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;route53_zone_name &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;example.com.&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;subdomain_name &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;vpn.example.com&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# vpc_cidr_block = &quot;10.0.0.0/16&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# subnet_cidr_block = &quot;10.0.0.0/16&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ssh_port = 22&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ssh_cidr = &quot;0.0.0.0/0&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# https_port = 443&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# https_cidr = &quot;0.0.0.0/0&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# tcp_port = 943&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# tcp_cidr = &quot;0.0.0.0/0&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# udp_port = 1194&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# udp_cidr = &quot;0.0.0.0/0&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# subdomain_ttl = 60&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ami = &quot;ami-f53d7386&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# instance_type = &quot;t2.medium&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# admin_user = &quot;openvpn&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# admin_password = &quot;openvpn&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;aws_profile_name = &amp;#x22;default&amp;#x22;aws_region = &amp;#x22;eu-west-1&amp;#x22;public_key = &amp;#x22;${file(&amp;#x22;key.pub&amp;#x22;)}&amp;#x22;private_key = &amp;#x22;${file(&amp;#x22;key&amp;#x22;)}&amp;#x22;certificate_email = &amp;#x22;tech@example.com&amp;#x22;route53_zone_name = &amp;#x22;example.com.&amp;#x22;subdomain_name = &amp;#x22;vpn.example.com&amp;#x22;# vpc_cidr_block = &amp;#x22;10.0.0.0/16&amp;#x22;# subnet_cidr_block = &amp;#x22;10.0.0.0/16&amp;#x22;# ssh_port = 22# ssh_cidr = &amp;#x22;0.0.0.0/0&amp;#x22;# https_port = 443# https_cidr = &amp;#x22;0.0.0.0/0&amp;#x22;# tcp_port = 943# tcp_cidr = &amp;#x22;0.0.0.0/0&amp;#x22;# udp_port = 1194# udp_cidr = &amp;#x22;0.0.0.0/0&amp;#x22;# subdomain_ttl = 60# ami = &amp;#x22;ami-f53d7386&amp;#x22;# instance_type = &amp;#x22;t2.medium&amp;#x22;# admin_user = &amp;#x22;openvpn&amp;#x22;# admin_password = &amp;#x22;openvpn&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The commented lines (starting with &lt;code&gt;#&lt;/code&gt;) are left for your own reference, in case you want to change one of the configuration defaults.&lt;/p&gt;
&lt;h3 id=&quot;plan-apply-and-destroy&quot;&gt;Plan, apply and destroy&lt;/h3&gt;
&lt;p&gt;Ok, we are finally ready to run our Terraform project.&lt;/p&gt;
&lt;p&gt;In order to see what changes will be applied to your AWS account, your will need to run:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;terraform&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;plan&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;terraform plan&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If you are happy with the displayed changes you can confirm them with:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;terraform&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;apply&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;terraform apply&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;After few minutes you will have a fully provisioned Virtual Private Cloud with its own VPN access. Try to connect to the domain (&lt;a href=&quot;https://vpn.example.com&quot;&gt;https://vpn.example.com&lt;/a&gt;) and login in with your admin username and password!&lt;/p&gt;
&lt;p&gt;Ok, this was probably just a test project for you so you might fancy cleaning everything up… No problem, just run:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;terraform&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;destroy&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;terraform destroy&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;and everything we just created will be blown away from your AWS account, leaving no trace behind!&lt;/p&gt;
&lt;h2 id=&quot;some-extra-tips&quot;&gt;Some extra tips&lt;/h2&gt;
&lt;p&gt;Just few extra tips before closing off…&lt;/p&gt;
&lt;h3 id=&quot;lets-encrypt-throttling&quot;&gt;Let’s Encrypt throttling&lt;/h3&gt;
&lt;p&gt;Let’s Encrypt allows you to generate a &lt;strong&gt;limited number of certificates for a given domain on a given timespan&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Quoting directly from &lt;a href=&quot;https://letsencrypt.org/docs/rate-limits/&quot;&gt;the Let’s Encrypt Rate Limit documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The main limit is &lt;strong&gt;Certificates per Registered Domain (20 per week)&lt;/strong&gt;. A registered domain is, generally speaking, the part of the domain you purchased from your domain name registrar. For instance, in the name &lt;a href=&quot;http://www.example.com&quot;&gt;www.example.com&lt;/a&gt;, the registered domain is example.com. In new.blog.example.co.uk, the registered domain is example.co.uk. We use the Public Suffix List to calculate the registered domain.&lt;/p&gt;
&lt;p&gt;If you have a lot of subdomains, you may want to combine them into a single certificate, up to a limit of 100 Names per Certificate. Combined with the above limit, that means you can issue certificates containing up to &lt;strong&gt;2,000 unique subdomains per week&lt;/strong&gt;. A certificate with multiple names is often called a SAN certificate, or sometimes a UCC certificate.&lt;/p&gt;
&lt;p&gt;We also have a &lt;strong&gt;Duplicate Certificate limit of 5 certificates per week&lt;/strong&gt;. A certificate is considered a duplicate of an earlier certificate if they contain the exact same set of hostnames, ignoring capitalization and ordering of hostnames. For instance, if you requested a certificate for the names [&lt;a href=&quot;http://www.example.com&quot;&gt;www.example.com&lt;/a&gt;, example.com], you could request four more certificates for [&lt;a href=&quot;http://www.example.com&quot;&gt;www.example.com&lt;/a&gt;, example.com] during the week. If you changed the set of names by adding [blog.example.com], you would be able to request additional certificates.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, be careful not to blow your production domain while playing with Terraform (or with certbot in general).&lt;/p&gt;
&lt;p&gt;There are options to generate &lt;em&gt;test&lt;/em&gt; or &lt;em&gt;staging&lt;/em&gt; certificates, although I haven’t experimented much with them, so I can only suggest you to have a look at the documentation illustration all the &lt;a href=&quot;https://certbot.eff.org/docs/using.html#certbot-command-line-options&quot;&gt;available command line options&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Huge thanks to &lt;a href=&quot;https://www.reddit.com/user/tialaramex&quot;&gt;tialaramex&lt;/a&gt; on Reddit for &lt;a href=&quot;https://www.reddit.com/r/linuxadmin/comments/6ia1wx/use_certbot_to_automate_the_creation_of_ssl/dj57zlw/&quot;&gt;a fruitful discussion&lt;/a&gt; and few pieces of advice about this specific aspect.&lt;/p&gt;
&lt;h3 id=&quot;certificate-expiry-and-renewal&quot;&gt;Certificate expiry and renewal&lt;/h3&gt;
&lt;p&gt;Let’s Encrypt &lt;strong&gt;certificates expire after 3 months&lt;/strong&gt;, so be sure you enable the auto renewal feature.&lt;/p&gt;
&lt;p&gt;In reality, the feature is enabled by default, so what’s left to do is to test the auto renewal process. With certbot you can do that using the following command:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;certbot&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;renew&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--dry-run&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;certbot renew --dry-run&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;There’s another important point here to take into account here: everytime the certificate renewal procedure is triggered, your VPN service gets shutdown for few seconds and all the currently connected users are disconnected.&lt;/p&gt;
&lt;p&gt;This will happen only once every 2-3 months, but if it’s a real struggle for your organisation you might want to explore different setups.&lt;/p&gt;
&lt;p&gt;One solution could be to setup a reverse proxy like Nginx and use it for the SSL termination. This way during the renewal you will only shutdown nginx and not the full VPN service.&lt;/p&gt;
&lt;p&gt;Thanks again to &lt;a href=&quot;https://www.reddit.com/user/tialaramex&quot;&gt;tialaramex&lt;/a&gt; on Reddit for raising this discussion and proposing the reverse proxy solution.&lt;/p&gt;
&lt;h3 id=&quot;intermittent-failures-during-the-provisioning&quot;&gt;Intermittent failures during the provisioning&lt;/h3&gt;
&lt;p&gt;I had some problems during the installation of certbot on the image used here by default. If this is happening to you as well, you should be able to sort them out by running an &lt;code&gt;apt-get upgrade&lt;/code&gt; before trying to install certbot. Since you want to do that in an automated fashion, you’ll probably need a more sophisticated command that takes care of auto-responding to possible prompts: &lt;code&gt;yes | sudo DEBIAN_FRONTEND=noninteractive apt-get upgrade&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;This is just a quick example focused on OpenVPN, but you can use the same approach to generate certificates for other web applications. Consult the &lt;a href=&quot;https://certbot.eff.org/docs/&quot;&gt;Certbot documentation &lt;/a&gt; to see all the supported web servers and how to use Certbot with them.&lt;/p&gt;
&lt;p&gt;Also, I hope this tutorial gave you a good idea on how to use Terraform to automate your infrastructure provisioning. I am still a bit of noob with it, so if you see I have done something terribly wrong (or something that can be improved), please let me know in the comments.&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href=&quot;https://twitter.com/Podgeypoos79&quot;&gt;@Podgeypoos79&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/tech_fort&quot;&gt;@techfort&lt;/a&gt;, &lt;em&gt;Alan&lt;/em&gt; and the rest of Planet 9 tech team for working with me on this cool 💩 (chocolate ice cream!). Also a huge thanks to my friend &lt;a href=&quot;https://twitter.com/gianarb&quot;&gt;@gianarb&lt;/a&gt; for some precious &lt;em&gt;devopsy&lt;/em&gt; bits of advice.&lt;/p&gt;
&lt;p&gt;Let me know in the comments if this article was useful for you and if you integrated something similar in one of your projects!&lt;/p&gt;
&lt;p&gt;See you in the next post :)&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/using-lets-encrypt-and-certbot-to-automate-the-creation-of-certificates-for-openvpn.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/using-lets-encrypt-and-certbot-to-automate-the-creation-of-certificates-for-openvpn.png" width="1200" height="630"/></media:content><category>ssl</category><category>web</category><category>terraform</category><category>security</category><category>aws</category><author>Luciano Mammino</author><comments>https://loige.co/using-lets-encrypt-and-certbot-to-automate-the-creation-of-certificates-for-openvpn/#comments</comments><enclosure url="https://loige.co/og/using-lets-encrypt-and-certbot-to-automate-the-creation-of-certificates-for-openvpn.png" length="0" type="image/png"/></item><item><title>From bare metal to Serverless</title><link>https://loige.co/from-bare-metal-to-serverless/</link><guid isPermaLink="true">https://loige.co/from-bare-metal-to-serverless/</guid><description>This article explores the history of cloud computing from bare metal servers to serverless, explaining key innovations like IaaS, PaaS, containers and FaaS along the way.</description><pubDate>Sat, 16 Dec 2017 19:23:20 GMT</pubDate><content:encoded>&lt;p&gt;Lately, I tried to understand why modern cloud computing brought us to the idea (and growing adoption) of “Serverless”.&lt;/p&gt;
&lt;p&gt;In this article, I will illustrate the result of a small research I did about the history of Cloud computing from the age of &lt;em&gt;bare metal&lt;/em&gt; to &lt;em&gt;serverless&lt;/em&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“You have to know the past to understand the present.”&lt;br&gt;
― Carl Sagan&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;At the end of this article, I will also illustrate a definition of Serverless and what are its main characteristics.&lt;/p&gt;
&lt;h2 id=&quot;the-invention-of-the-web&quot;&gt;The invention of the web&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;1989-1991 — Sir Tim Berners-Lee invented the World Wide Web&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2000&quot; height=&quot;1125&quot; src=&quot;https://loige.co/_astro/web-www-tim-berners-lee-from-bare-metal-to-serverless.Cv0pltQb_Z1gHLCJ.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;This story starts with &lt;a href=&quot;https://en.wikipedia.org/wiki/Tim_Berners-Lee&quot;&gt;Sir Tim Berners Lee&lt;/a&gt;, the guy who officially invented the World Wide Web in 1989.&lt;/p&gt;
&lt;p&gt;At the beginning, the web was just a simple publishing platform for researchers to share information and publish papers. The first website was actually the CERN website, published in 1991.&lt;/p&gt;
&lt;p&gt;The web quickly evolved and grew up out of the research space, to become one of the most mainstream and ubiquitous products of the last decades.&lt;/p&gt;
&lt;h2 id=&quot;the-bare-metal-age&quot;&gt;The bare metal age&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;1991-1995 — The bare metal age&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://loige.co/_astro/server-racks-bare-metal-age-google-from-bare-metal-to-serverless.B4f-9rko_1dKWkJ.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;During the first years of the web, publishing a website wasn’t very easy. We are talking about a period that goes roughly from 1991 to 1995.&lt;/p&gt;
&lt;p&gt;At that time you literally had to buy your server machine, configure it, connect it to a stable electricity line and to an internet connection and then run a web server on it. You had to take care of every single aspect of making that server always available.&lt;/p&gt;
&lt;p&gt;Can you imagine the effort required when you needed to scale your service and adopt many servers?&lt;/p&gt;
&lt;h2 id=&quot;the-invention-of-web-hosting&quot;&gt;The invention of web hosting&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;1995 — The invention of web hosting&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://loige.co/_astro/geocities-invention-of-web-hosting-from-bare-metal-to-serverless.CXDjF7jP_Z2lDHXd.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;During 1995, the idea of the web hosting was popularised by platforms like &lt;a href=&quot;https://en.wikipedia.org/wiki/Yahoo!_GeoCities&quot;&gt;GeoCities&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Web hosting allowed everybody to publish web pages directly on shared servers at a very low cost (sometimes even for free), removing from the publisher all the struggle and the costs needed with the bare metal approach.&lt;/p&gt;
&lt;p&gt;Although web hosting was cheap and easy, most of the time it was very limited and it was possible to publish only static files (HTML, images, etc.) through FTP. Later on, web hosting improved supporting dynamic languages like Perl and PHP and databases like MySQL.&lt;/p&gt;
&lt;h2 id=&quot;grid-computing&quot;&gt;Grid computing&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;1997 Ian Foster and the idea of Grid Computing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://loige.co/_astro/ian-foster-grid-computing-from-bare-metal-to-serverless.B2E9l8iU_Z1F43Je.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Around 1997, thanks to the astonishing work of the University of Chicago and the Argonne National Laboratory, that together founded the &lt;a href=&quot;https://en.m.wikipedia.org/wiki/Globus_Alliance&quot;&gt;Globus Alliance&lt;/a&gt;, the idea of &lt;em&gt;Grid computing&lt;/em&gt; was formalized.&lt;/p&gt;
&lt;p&gt;In a paper titled &lt;em&gt;“Globus: A Metacomputing Infrastructure Toolkit”&lt;/em&gt; by Ian Foster (in the picture) and Carl Kesselman, a new idea of computing, defined &lt;em&gt;metacomputing&lt;/em&gt;, was formalized and finally made famous:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Metacomputing&lt;/strong&gt;: a networked virtual supercomputer, constructed dynamically from geographically distributed resources linked by high-speed networks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Metacomputing is the foundation for Grid Computing which is generally recognized as the collection of computer resources from multiple locations to reach a common goal. The grid can be thought of as a distributed system with non-interactive workloads that involve a large number of files and tasks.&lt;/p&gt;
&lt;p&gt;Grid computing was important for the history of the cloud because it shifted the perception on the power of distributed computing. It was the demonstration that the world didn’t need a single supercomputer in order to solve complex problems, because a well-knitted network of ordinary computers can be orchestrated to achieve complex goals or to sustain sophisticated services.&lt;/p&gt;
&lt;h2 id=&quot;software-as-a-service-saas&quot;&gt;Software as a Service (SaaS)&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;1999 — Salesforce introduces the concept of Software as a Service (SaaS)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://loige.co/_astro/marc-benioff-salesforce-software-as-a-service-from-bare-metal-to-serverless.BNS5EXfJ_Z1zWhYw.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;In 1999 the web was starting to evolve into something more complex, Amazon.com was already a thing and it was already possible to build complex interactions with the users through the browser.&lt;/p&gt;
&lt;p&gt;Marc Benioff of Salesforce was one of the first public figures to strongly state the desktop software wasn’t needed anymore and it could have been replaced by software written to work directly on the web through a web browser.&lt;/p&gt;
&lt;p&gt;This principle, lead in the following years to the definition of &lt;em&gt;Software as a Service&lt;/em&gt; (SaaS) and it was probably the reason why the web started to play a bigger role, not only as a publishing platform but as a complete runtime to execute all sorts of applications and games.&lt;/p&gt;
&lt;h2 id=&quot;server-virtualization&quot;&gt;Server virtualization&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;2001 — VMWare releases ESXi, &amp;quot;server virtualization&amp;quot; becomes a thing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://loige.co/_astro/VMware-BIOS-server-virtualization-from-bare-metal-to-serverless.D1680y9C_ZP5t9e.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;In 2001, VMWare releases ESXi and server virtualization becomes a thing.&lt;/p&gt;
&lt;p&gt;With server virtualization, it’s possible to divide one physical server into multiple isolated virtual environments.&lt;/p&gt;
&lt;p&gt;This way the provider can allocate a number of physical machines in advance in their server farms to create a virtual infrastructure in which a new virtual machine (with variable characteristics) can be initialized and provided as a service in a matter of minutes.&lt;/p&gt;
&lt;p&gt;This approach is way more convenient and flexible than the bare metal one.&lt;/p&gt;
&lt;p&gt;Interesting thing is that virtualization was a thing way back in the history of computing. For example, CP-40 was a research project back in 1964 that ran on the 360. IBM released a product from that called VM in 1972. This eventually turned into z/VM, which has a long line of products before it.&lt;/p&gt;
&lt;h2 id=&quot;infrastructure-as-a-service-iaas&quot;&gt;Infrastructure as a service (IaaS)&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;2002-2006 — AWS is born (IaaS), people talk about &amp;quot;Cloud computing&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://loige.co/_astro/andy-jassy-aws-reinvent-infrastructure-as-a-service-from-bare-metal-to-serverless.DvApA30__1HVReo.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;From 2002 and 2006 Amazon Web Services, a company spawn up by the opportunity that Amazon saw with renting part of their massive compute power, undergo 3 different “official launch” events.&lt;/p&gt;
&lt;p&gt;Only after the 3rd launch, AWS found the right proposition to developers and started to build up significant traction. This successful launch defined the term &lt;em&gt;Infrastructure as a Service&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;At the time AWS offer constituted by EC2 (Virtual Machine service), S3 (Scalable storage service) and SQS (message queuing system).&lt;/p&gt;
&lt;p&gt;In the years to come, AWS and the competing IaaS platforms would have been associated with the idea of &lt;em&gt;“Cloud Computing”&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;platform-as-a-service-paas&quot;&gt;Platform as a Service (PaaS)&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;2009 — Heroku and the invention of the &amp;quot;Platform as a Service&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://loige.co/_astro/adam-wiggins-heroku-founder-from-bare-metal-to-serverless.8u2uMVdn_1QJMx7.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Heroku was developed by James Lindenbaum, Adam Wiggins (in the picture) and Orion Henry in 2009.&lt;/p&gt;
&lt;p&gt;Heroku was originally born as an attempt to create an online editor for Ruby on Rails, but it quickly found it’s &lt;em&gt;product-market fit&lt;/em&gt; as a complete platform to deploy and scale Ruby web applications. Support later increasingly extended to all the main languages and frameworks in the market.&lt;/p&gt;
&lt;p&gt;Heroku defined the idea of &lt;em&gt;Platform as a Service&lt;/em&gt; (PaaS) and it was so successful that Salesforce acquired the company and hired Yukihiro Matsumoto, the inventor of Ruby, as Chief Architect a few years later.&lt;/p&gt;
&lt;h2 id=&quot;database-as-a-service&quot;&gt;Database as a service&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;2011 — Envolve/Firebase, real-time database as a service&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://loige.co/_astro/firebase-founder-james-tamplin-from-bare-metal-to-serverless.SEhqJUJ3_Z1fWiwn.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Firebase evolved from Envolve, a prior startup founded by James Tamplin (in the picture) and Andrew Lee in 2011.&lt;/p&gt;
&lt;p&gt;The main idea of Firebase was to provide a real-time database as a service through a dedicated SDK that could be easily integrated with websites and mobile applications.&lt;/p&gt;
&lt;p&gt;This was one of the first successful instances where a database could have been used with a pay-per-use model.&lt;/p&gt;
&lt;p&gt;Firebase was so successful that a few years later it was acquired by Google and evolved again into a complete platform for supporting the development of mobile apps.&lt;/p&gt;
&lt;p&gt;Little curiosity: for some reason nobody (as far as I am aware) tried to come up with a short name such as &lt;em&gt;DBaaS&lt;/em&gt; or &lt;em&gt;RTDBaaS&lt;/em&gt;!&lt;/p&gt;
&lt;h2 id=&quot;backend-as-a-service-baas&quot;&gt;Backend as a service (BaaS)&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;2012 — Parse.com and the first Backend as a Service (BaaS)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://loige.co/_astro/ilya-sukhar-parse-com-founder-from-bare-metal-to-serverless.CLeL7MTc_1iEdKX.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Parse was founded in 2011 by Tikhon Bernstam, Ilya Sukhar (in the picture), James Yu, and Kevin Lacker.&lt;/p&gt;
&lt;p&gt;The firm produced a series of back-end tools for mobile developers to store data in the cloud, manage identity log-ins, handle push notifications and run custom code in the cloud. This kind of product was known at the time as &lt;em&gt;Backend as a Service&lt;/em&gt; (Baas).&lt;/p&gt;
&lt;p&gt;The company was later on acquired by Facebook that kept it running for a while and then it shut it down. The product was consequently &lt;a href=&quot;http://parseplatform.org&quot;&gt;released&lt;/a&gt; with an open source license and can be installed on-premise.&lt;/p&gt;
&lt;h2 id=&quot;containerization&quot;&gt;Containerization&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;2013 — Docker, &amp;quot;containers are better than virtual machines&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://loige.co/_astro/solomon-hykes-dockercon-docker-container-from-bare-metal-to-serverless.6KVGkYx7_ZrPKSl.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Docker, launched in 2013 at pyCon by Solomon Hykes, provides an additional layer of abstraction and automation of operating-system-level virtualization on Windows and Linux.&lt;/p&gt;
&lt;p&gt;Docker can be used as a way to package applications so that they can be easily executed on various servers without having to worry about the underlying infrastructure.&lt;/p&gt;
&lt;p&gt;The funny story is that docker was originally created as a way to abstract the underlying infrastructure at dotCloud, a competitor of Heroku that a few years later bankrupted, while docker became a huge success and it is today adopted or supported by almost every cloud provider.&lt;/p&gt;
&lt;h2 id=&quot;containers-at-scale&quot;&gt;Containers at scale&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;2013-2015 — Kubernetes / Swarm / Nomad / CoreOs (containers at scale)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://loige.co/_astro/google-cloud-kubernetes-from-bare-metal-to-serverless.CUg9ALKB_1DAS9t.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;The launch of Docker was a blast and its potential was immense.&lt;/p&gt;
&lt;p&gt;During the following years, a lot of companies (including Google and Hashicorp) started to invest a significant amount of money and energy to create solutions that leveraged docker to run containers on a large scale, like Kubernetes, Swarm, Nomad and CoreOs.&lt;/p&gt;
&lt;p&gt;The idea was to use containers as an abstraction to run processes and applications over a cluster of virtual machines.&lt;/p&gt;
&lt;h2 id=&quot;function-as-a-service-faas&quot;&gt;Function as a Service (FaaS)&lt;/h2&gt;
&lt;p&gt;&lt;img  loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://loige.co/_astro/aws-lambda-launch-faas-function-as-a-service-from-bare-metal-to-serverless.ChJr1l8S_2atAU7.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;In 2014 AWS launched Lambda, a service that allowed to run “code”, in the form of a function, directly in the cloud.&lt;/p&gt;
&lt;p&gt;In Lambda the computation model is event based, which means that a function is executed only if a predefined event occurred.&lt;/p&gt;
&lt;p&gt;This product popularised a new class of services called Function as a Service (FaaS).&lt;/p&gt;
&lt;p&gt;With the advent of FaaS we started to hear the word “Serverless” for the first time.&lt;/p&gt;
&lt;h2 id=&quot;what-is-serverless&quot;&gt;What is Serverless&lt;/h2&gt;
&lt;p&gt;Trying to define what Serverless actually means is always a bit tricky, so I prefer to give you two definitions by two acclaimed industry leaders in this field.&lt;/p&gt;
&lt;p&gt;The first lengthy definition comes straight from Amazon Web Services:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Serverless most often refers to &lt;strong&gt;serverless applications&lt;/strong&gt;. Serverless applications are ones that &lt;strong&gt;don’t require you to provision or manage any servers&lt;/strong&gt;. You can &lt;strong&gt;focus on your core product and business logic&lt;/strong&gt; instead of responsibilities like operating system (OS) access control, OS patching, provisioning, right-sizing, scaling, and availability. By building your application on a serverless platform, the platform manages these responsibilities for you.”&lt;/p&gt;
&lt;p&gt;— &lt;a href=&quot;http://loige.link/serverless-apps-lambda&quot;&gt;Amazon Web Services&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A much more concise one (that I prefer) comes from Auth0:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The essence of the serverless trend is the absence of the server concept during software development.&lt;/p&gt;
&lt;p&gt;— &lt;a href=&quot;http://loige.link/what-is-serverless&quot;&gt;Auth0&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I hope you got the point. Serverless doesn’t mean that there are no servers, of course, there’s a server somewhere, but as a developer, you don’t get to worry about it and you can focus as much as possible on the business logic of the application you are working on.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://loige.link/serverless-commitstrip&quot;&gt;&lt;img alt=&quot;You told me there were no servers!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;650&quot; height=&quot;618&quot; src=&quot;https://loige.co/_astro/commitstrip-strip-severless-from-bare-metal-to-serverless.CWeC3hsN_6mfJl.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Picture from &lt;a href=&quot;https://commitstrip.com&quot;&gt;commitstrip.com&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-serverless&quot;&gt;Why Serverless?&lt;/h2&gt;
&lt;p&gt;The history we explored so far is telling that our industry has always been looking for next higher level of abstraction. Developers need as fewer concerns as possible to be able to quickly release features and deliver value to the customers.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Serverless through abstractions&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1492&quot; height=&quot;486&quot; src=&quot;https://loige.co/_astro/serverless-abstraction-levels-fullstack-python-from-bare-metal-to-serverless.dQdAWYOi_Z2lsBdN.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Picture from &lt;a href=&quot;https://www.fullstackpython.com/serverless.html&quot;&gt;fullstackpython.com&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;In this picture, Matt Makai from &lt;em&gt;fullstackpython&lt;/em&gt;, illustrates exactly how levels of abstraction and platforms were created to keep removing complexity and leave more time for the actual business value that the app has to provide.&lt;/p&gt;
&lt;p&gt;Serverless today is the highest level of abstraction we have. It is not perfect and there are strong trade-offs that a developer has to embrace in order to adopt it, but it definitely removes tons of concerns on the infrastructure layer.&lt;/p&gt;
&lt;h2 id=&quot;the-4-pillars-of-serverless&quot;&gt;The 4 pillars of Serverless&lt;/h2&gt;
&lt;p&gt;There are other characteristics that come with Serverless and that make it a valuable option. It’s definitely not only about abstraction and the absence of servers…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No server management&lt;/strong&gt;: You don’t know how many and how they are configured&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flexible scaling&lt;/strong&gt;: If you need more resources, they will be allocated for you&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;High availability&lt;/strong&gt;: Redundancy and fault tolerance are built in&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Never pay for idle&lt;/strong&gt;: Unused resources cost $0&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;is-it-the-right-approach-for-the-future&quot;&gt;Is it the right approach for the future?&lt;/h2&gt;
&lt;p&gt;My personal view, &lt;strong&gt;probably yes&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Like any other abstraction, Serverless comes with some strong trade-offs (vendor lock-in, steep learning curve, cold start problem, soft/hard limits, etc.), but it allows us, as developers, to focus more and more on building and releasing value as fast as possible.&lt;/p&gt;
&lt;p&gt;We live in a time where the competition on the web is at its highest, there is practically no decent idea that somebody else is not already attempting to implement (or that have already successfully implemented!) and it is critical to be able to be on the market quickly and be able to iterate and improve a product efficiently.&lt;/p&gt;
&lt;p&gt;Serverless can give you the needed agility to compete in this market for most of the cases, but you have to be willing to learn it and embrace its trade-offs.&lt;/p&gt;
&lt;p&gt;It’s probably not the ultimate solution and I believe there will be other abstraction layers and new platforms in the future, but agility and focus on business logic are definitely some things that we will always want in our future as developers.&lt;/p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;p&gt;This article was possible only thanks to these amazing resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://webfoundation.org/about/vision/history-of-the-web/&quot;&gt;World Wide Web Foundation, history of the web&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Web_hosting_service&quot;&gt;Web hosting on Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://loige.link/web-hosting-history&quot;&gt;The history of web hosting: how things have changed since Tibus started in 1996&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.m.wikipedia.org/wiki/Grid_computing&quot;&gt;Grid computing on Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.m.wikipedia.org/wiki/Globus_Toolkit&quot;&gt;Globus toolkit on Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.m.wikipedia.org/wiki/Globus_Alliance&quot;&gt;Globus Alliance on Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://ssltest.cs.umd.edu/class/spring2004/cmsc818s/Lectures/Globus.pdf&quot;&gt;Globus: A Metacomputing Infrastructure Toolkit (slides)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://journals.sagepub.com/doi/abs/10.1177/109434200101500302&quot;&gt;The Anatomy of the Grid: Enabling Scalable Virtual Organizations (paper)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://computerweekly.com/feature/A-history-of-cloud-computing&quot;&gt;Computer weekly, the history of Cloud Computing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://salesforceben.com/brief-history-salesforce-com&quot;&gt;Brief history of Salesforce.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.networkworld.com/article/2254433/virtualization/with-long-history-of-virtualization-behind-it--ibm-looks-to-the-future.html&quot;&gt;With long history of virtualization behind it, IBM looks to the future&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://aws.amazon.com/about-aws&quot;&gt;About Amazon Web Services (official)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://fullstackpython.com/serverless.html&quot;&gt;Fullstack python: What is Serverless&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Parse_(platform)&quot;&gt;Parse (platform) on Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Firebase&quot;&gt;Firebase on Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Kubernetes&quot;&gt;Kubernetes on Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Container_Linux_by_CoreOS&quot;&gt;CoreOS on Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/AWS_Lambda&quot;&gt;AWS Lambda on Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Serverless_computing&quot;&gt;Serverless Computing on Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://loige.link/aws-serverless-lens&quot;&gt;“AWS Serverless Applications Lens” white paper (pdf)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://loige.link/serverless-apps-lambda&quot;&gt;“Serverless Architectures with AWS Lambda” white paper (pdf)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://start.jcolemorrison.com/aws-lambda-vs-the-world&quot;&gt;AWS Lambda VS the World&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://m.subbu.org/serverless-looking-back-to-see-forward-74dd1a02cb62&quot;&gt;Serverless: Looking Back to See Forward&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/anaibol/awesome-serverless&quot;&gt;Awesome Serverless (GitHub repository)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lobste.rs/s/pehagh/from_bare_metal_serverless&quot;&gt;Discussion about this article on Lobste.rs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, I had the pleasure to discuss this topic in the recent &lt;a href=&quot;https://frontconf.com&quot;&gt;FrontConf 2017&lt;/a&gt; in Munich in a presentation titled “The future will be SERVERLESS”. Feel free to check out &lt;a href=&quot;http://loige.link/serverless-future&quot;&gt;the slides deck&lt;/a&gt; and give me your precious feedback.&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/from-bare-metal-to-serverless.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/from-bare-metal-to-serverless.png" width="1200" height="630"/></media:content><category>serverless</category><category>aws</category><author>Luciano Mammino</author><comments>https://loige.co/from-bare-metal-to-serverless/#comments</comments><enclosure url="https://loige.co/og/from-bare-metal-to-serverless.png" length="0" type="image/png"/></item><item><title>AWS Solution Architect Associate exam, my notes and tips</title><link>https://loige.co/aws-solution-architect-associate-exam-notes-tips/</link><guid isPermaLink="true">https://loige.co/aws-solution-architect-associate-exam-notes-tips/</guid><description>The AWS Solutions Architect Associate exam covers a wide range of AWS services. This post shares helpful notes and tips for studying key concepts like EC2, S3, VPC, DynamoDB, and more. It provides advice on the exam mindset and lists official and unofficial preparation resources. The notes summarize important details around provisioned throughput, instance types, database replication and more that are helpful to know for the exam.</description><pubDate>Sun, 21 Oct 2018 11:57:00 GMT</pubDate><content:encoded>&lt;p&gt;In this article, I will share some of my notes and tips that might be useful if you are studying to get the AWS Solution Architect Associate Certification.&lt;/p&gt;
&lt;p&gt;I recently took this certification and I have to admit it was a little bit more challenging than I originally expected. I have been using a variety of AWS services professionally in the last 3 years, so I was optimistically expecting this practical experience to be enough. In reality, I had to spend some time to study and fill some gaps about important topics or details that I never had to deal with during my professional experience.&lt;/p&gt;
&lt;p&gt;In this article, I will try to recap some of the topics I believe are important to know for this specific certification with a particular focus on things that I struggled a bit to remember or that I generally tripped over during the quiz simulations.&lt;/p&gt;
&lt;p&gt;Hopefully, if you are preparing for the same certification, this article will be helpful to you! 😊&lt;/p&gt;
&lt;h2 id=&quot;mindset&quot;&gt;Mindset&lt;/h2&gt;
&lt;p&gt;The exam is a classic quiz where you have to pick one or more answers. It’s very easy to find simulations online, so you might be tempted to spend your time just doing that and use the quiz experience as a way to learn what’s necessary to pass the exam.&lt;/p&gt;
&lt;p&gt;While this might be good to understand the style of the questions and the depth of the topics covered, you shouldn’t try to learn specific questions and answers by heart. In fact, studying quiz questions and memorizing answer is NOT a good study technique and it will be likely reducing your chances of passing the exam, rather than increasing it!&lt;/p&gt;
&lt;p&gt;All the questions are quite reasonable, if you understood the theory behind all the different AWS services and you know the most important details (in terms of costs, configuration, availability, durability, etc.), you should be able to figure out the right answers.&lt;/p&gt;
&lt;p&gt;I admit some questions might be tricky. For instance, you might get questions where more than one answer seems to be correct. In those cases, it might be helpful to try to reason by exclusion and look for all the answers that are definitely wrong. If this is still not helping you to come up to a definitive answer, you can still “flag” the question (yeah, that’s an option in the examination platform) and come back to it later with a fresher mind.&lt;/p&gt;
&lt;p&gt;Managing your time will be important too. Try not to spend more than 2 or 3 minutes per question. If you feel you are spending too much time on a question, again, you can flag it and come back to it later when you addressed all the others. In short, make sure you addressed all the questions you feel sure about and save some time to address and review the ones you are struggling with. Sometimes, a bit more reasoning will help you identify some key detail you were initially missing to unlock the right answer.&lt;/p&gt;
&lt;h2 id=&quot;study-and-exercise-material&quot;&gt;Study and exercise material&lt;/h2&gt;
&lt;p&gt;I used a number of different sources to prepare for the exam.
The mandatory place to start with is the &lt;a href=&quot;https://aws.amazon.com/certification/certified-solutions-architect-associate/&quot;&gt;official AWS Solution Architect Associate certification page&lt;/a&gt;. In this page you will find all the necessary details about the certification and links to the two most important official (FREE) resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/architecture/well-architected/&quot;&gt;The AWS Well-architected framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://d0.awsstatic.com/whitepapers/AWS_Cloud_Best_Practices.pdf&quot;&gt;Best practices: architecting for the cloud&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also used other unofficial resources. A big shout out goes to &lt;a href=&quot;https://acloud.guru/&quot;&gt;A Cloud Guru&lt;/a&gt;, which offers a subscription that allows to watch all video series for all sorts of AWS certifications. In my personal opinion, the format of the courses is great. It is particularly focused on explaining the fundamental principles of every single service but it is also very practical in underlining what’s really important to know in order to be ready the exam. Their platform also offers per topic quiz and exercises, but also a complete exam simulation app.&lt;/p&gt;
&lt;p&gt;In the last few days of my preparation, I also found an interesting (and FREE) Android app called &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.magycbytes.aws&quot;&gt;
AWS Certified Solutions Architect Associate (by Magic Bytes Soft)&lt;/a&gt;. The app offers nice features to test your knowledge like flash cards and test sessions.&lt;/p&gt;
&lt;p&gt;Finally, when you feel confident enough with the exam simulations, it might be a good idea to tackle the &lt;a href=&quot;https://aws.amazon.com/training/&quot;&gt;official exam simulation by AWS Training&lt;/a&gt; (paid) to have a better feeling of what the platform looks like and what kind of questions can you expect.&lt;/p&gt;
&lt;p&gt;Take into account that some practical experience with AWS is very important. Of course you can understand all the concepts only at a theoretical level, but practice will be very important to fix those concepts in your mind and to understand why many details are important. So be sure you spend some time playing around with all the services you might not have used yet. In those cases, I found that trying to build a little side project that involves those services is often the most complete and rewarding experience.&lt;/p&gt;
&lt;h2 id=&quot;my-notes&quot;&gt;My Notes&lt;/h2&gt;
&lt;p&gt;Here’s a collection of notes that I took during my studies, somewhat organized by topic/service. Again, these notes don’t aim to be comprehensive but they might still be useful to recap some of the most important aspects of all the different services (that’s at least why I compiled this list for myself).&lt;/p&gt;
&lt;h3 id=&quot;cloud-computing-and-aws-concepts&quot;&gt;Cloud Computing and AWS concepts&lt;/h3&gt;
&lt;h4 id=&quot;durability--availability&quot;&gt;Durability &amp;#x26; Availability&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Durability&lt;/strong&gt; can be described as the probability that you will eventually be able to get your object back from the storage system from one of the stores and archives (objects persist during time).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Availability&lt;/strong&gt; is the probability that you will be able to get an object back the moment that you ask for it (i.e. the object might still be persistent, but that doesn’t necessarily mean you can read it all the time - think of momentary networking or system issues).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;the-well-architected-framework&quot;&gt;The Well-Architected Framework&lt;/h4&gt;
&lt;p&gt;The Well-Architected Framework is a guide that proposes a set of questions that you can use to evaluate how well your architecture is aligned to AWS practices.
It will help you design architectures that can achieve:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Operational Excellence&lt;/li&gt;
&lt;li&gt;Security&lt;/li&gt;
&lt;li&gt;Reliability&lt;/li&gt;
&lt;li&gt;Performance Efficiency&lt;/li&gt;
&lt;li&gt;Cost Optimization&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those are sometimes referred to as &lt;strong&gt;5 pillars&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Sometimes, you’ll see a misleading “Availability” (pillar) in the possible answers of the quiz.&lt;/p&gt;
&lt;h4 id=&quot;aws-support-plans&quot;&gt;AWS Support plans&lt;/h4&gt;
&lt;p&gt;There are 4 plans available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Basic&lt;/li&gt;
&lt;li&gt;Developer&lt;/li&gt;
&lt;li&gt;Business&lt;/li&gt;
&lt;li&gt;Enterprise&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the quizzes, you’ll often see a misleading “Corporate” plan which does not exist&lt;/p&gt;
&lt;h4 id=&quot;web-console-saml-authentication-flow&quot;&gt;Web console SAML authentication flow&lt;/h4&gt;
&lt;p&gt;SAML allows configuring federated user access to the corporate AWS account (basically you can re-use your corporate user management system to grant access to AWS and avoid to replicate all your users into IAM).&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The flow starts from the corporate portal (not on the AWS console)&lt;/li&gt;
&lt;li&gt;The user triggers the auth on the corporate portal which verifies the user identity&lt;/li&gt;
&lt;li&gt;The portal generates a SAML authentication response that includes assertions and attributes about the user&lt;/li&gt;
&lt;li&gt;The client browser is then redirected to the AWS single sign-on endpoint posting the SAML assertion&lt;/li&gt;
&lt;li&gt;The AWS console endpoint validates the SAML assertion and generates a redirect to access the management console (suing STS)&lt;/li&gt;
&lt;li&gt;The browser follows the redirect which brings into the AWS console as an authenticated user&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;More info available in &lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-saml.html&quot;&gt;Enabling SAML 2.0 Federated Users to Access the AWS Management Console&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;s3&quot;&gt;S3&lt;/h3&gt;
&lt;p&gt;AWS Object Storage Solution.&lt;/p&gt;
&lt;h4 id=&quot;consistency-model&quot;&gt;Consistency model&lt;/h4&gt;
&lt;h5 id=&quot;read-after-write-consistency&quot;&gt;Read after write consistency:&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PUT&lt;/code&gt; (New files)&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;eventual-consistency&quot;&gt;Eventual consistency:&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PUT&lt;/code&gt; (updates)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DELETE&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Updates are atomic&lt;/strong&gt;: requesting a file immediately after an update will give you either the old data or the new data (no partially updated or corrupted data).&lt;/p&gt;
&lt;h4 id=&quot;storage-classes&quot;&gt;Storage classes&lt;/h4&gt;
&lt;h5 id=&quot;frequent-access&quot;&gt;Frequent Access:&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;STANDARD&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;REDUCED_REDUNDANCY (RRS)&lt;/code&gt;: for non-critical and reproducible data, you might be losing up to 0.01% of all your objects per year&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;infrequent-access-pay-per-read&quot;&gt;Infrequent Access (pay per read):&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;STANDARD_IA&lt;/code&gt;: grant quick reads (small latency), but you pay per read.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ONEZONE_IA&lt;/code&gt;: like &lt;code&gt;STANDARD_IA&lt;/code&gt;, but stored only in one availability zone, less availability (if that specific zone is down you won’t be able to access the files until the zone is back)&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;archive&quot;&gt;Archive&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GLACIER&lt;/code&gt;: data is archived and needs to be explicitly restored (which takes 3-5 hours) to be available again. Cheapest solution.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;durability--availability-table&quot;&gt;Durability &amp;#x26; Availability table&lt;/h4&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;Class&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;Durability&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;Availability&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;STANDARD&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;99,999999999%&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;99,99%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;STANDARD_IA&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;99,999999999%&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;&lt;strong&gt;99,9%&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;ONEZONE_IA&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;99,999999999%&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;&lt;strong&gt;99,5%&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;GLACIER&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;99,999999999%&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;99,99%&lt;sup&gt;*&lt;/sup&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;REDUCED_REDUNDANCY&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;&lt;strong&gt;99,99%&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;99,99%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;legend&gt;&lt;sup&gt;*&lt;/sup&gt; After restore&lt;/legend&gt;
&lt;ul&gt;
&lt;li&gt;Durability is always &lt;em&gt;11 nines&lt;/em&gt; (99,999999999%) except for &lt;code&gt;REDUCED_REDUNDANCY&lt;/code&gt;, suitable for cases where you might afford to lose files (e.g. you can regenerate them).&lt;/li&gt;
&lt;li&gt;Availability is almost always 99,99% except for &lt;code&gt;STANDARD_IA&lt;/code&gt; (99,9%) and &lt;code&gt;ONEZONE_IA&lt;/code&gt; (99,5%), these are suitable for cases where you rarely have to access the data, but when you need to it has to be as fast as STANDARD (can’t wait hours like with GLACIER).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;encryption-features&quot;&gt;Encryption features&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SSE-S3&lt;/strong&gt;: fully managed encryption at rest (don’t have to worry about encryption keys)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSE-C&lt;/strong&gt;: encryption at rest with custom encryption keys (to be provided together with the uploaded or download the file). The key is not stored by AWS. Use this option if you want to maintain your own encryption keys, but don’t want to implement or leverage a client-side encryption library.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSE-KMS&lt;/strong&gt;: encryption at rest using keys managed through the KMS service. Allows to define fine grained permissions based on the permissions of KMS keys. Best solution for compliance (PCI-DSS, HIPAA, etc.).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;mfa-delete&quot;&gt;MFA Delete&lt;/h4&gt;
&lt;p&gt;For extra security S3 supports the option “MFA on delete” which requests a user to enter an MFA code to be able to delete a file. Protects against accidental or unauthorized deletions.&lt;/p&gt;
&lt;h4 id=&quot;transfer-optimizations&quot;&gt;Transfer optimizations&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;If latency is an issue you can use &lt;strong&gt;S3 transfer acceleration&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If transfer speed is a problem or you have to transfer big files through HTTP you can use &lt;strong&gt;multi-part upload&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If you need to transfer massive amount of data into AWS and it might take too long to do that on the wire you can use &lt;strong&gt;Snowball&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If your storage needs to exist also on premise (hybrid cloud storage), you can use &lt;strong&gt;Storage gateway&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storage gateway&lt;/strong&gt; offers 2 main volume modes:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cached volumes&lt;/strong&gt;: stores files in the cloud and keeps a local cache to speed up reads&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stored volumes&lt;/strong&gt;: optimized for low latency, stores files locally and asynchronously sends back up point-in-time snapshots to S3.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;cross-region-replication-crr&quot;&gt;Cross Region Replication (CRR)&lt;/h4&gt;
&lt;p&gt;Cross-region replication requires the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Both source and destination buckets must have versioning enabled.&lt;/li&gt;
&lt;li&gt;The source and destination buckets must be in different AWS Regions (that’s why it’s called cross-region!)&lt;/li&gt;
&lt;li&gt;Amazon S3 must have permissions to replicate objects from the source bucket to the destination bucket on your behalf.&lt;/li&gt;
&lt;li&gt;If the owner of the source bucket doesn’t own the object in the bucket, the object owner must grant the bucket owner &lt;code&gt;READ&lt;/code&gt; and &lt;code&gt;READ_ACP&lt;/code&gt; permissions with the object ACL.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;defaults--limits&quot;&gt;Defaults / Limits&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Max object size: 5TB&lt;/li&gt;
&lt;li&gt;Min object size: 0bytes, except for S3 IA that has a min size of 128kb.&lt;/li&gt;
&lt;li&gt;Default maximum number of buckets per region: 100&lt;/li&gt;
&lt;li&gt;Bucket/Object url format: &lt;code&gt;http://${BUCKET_NAME}.s3.amazonaws.com/${OBJECT_KEY}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;other&quot;&gt;Other&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;S3 can be used to host (static) websites (URL schemas: &lt;code&gt;&amp;#x3C;bucket-name&gt;.s3-website-&amp;#x3C;AWS-region&gt;.amazonaws.com&lt;/code&gt; and &lt;code&gt;&amp;#x3C;bucket-name&gt;.s3-website.&amp;#x3C;AWS-region&gt;.amazonaws.com&lt;/code&gt;). You can use Cloudfront as a CDN to make the website fast globally.&lt;/li&gt;
&lt;li&gt;S3 website can be configured to do redirects.&lt;/li&gt;
&lt;li&gt;Glacier files can be restored through the web console or the S3 API (RestoreRequest action).&lt;/li&gt;
&lt;li&gt;Only the owner of an Amazon S3 bucket can permanently delete a version.&lt;/li&gt;
&lt;li&gt;S3 can achieve at least 3,500 PUT/POST/DELETE and 5,500 GET requests per second per prefix in a bucket (you can use random prefixes to increase the throughput in data-intensive applications).&lt;/li&gt;
&lt;li&gt;You can write objects directly to an edge location (for instance, this is useful if you are letting users of an app upload files directly to S3 and you want to reduce latency world wide).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;sqs&quot;&gt;SQS&lt;/h3&gt;
&lt;p&gt;AWS distributed queue service.&lt;/p&gt;
&lt;h4 id=&quot;types-of-queue&quot;&gt;Types of queue&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Standard&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Extremely high throughput (AWS defines it “nearly unlimited”), highly distributed&lt;/li&gt;
&lt;li&gt;Messages are guaranteed to be delivered “at-least-once” (sometimes a message can be delivered more than once)&lt;/li&gt;
&lt;li&gt;Best-effort ordering (messages are generally delivered in order, but they might be occasionally out of order)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FIFO (First-In-First-Out)&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;Limited number of transactions per second (3000 TPS with batching, 300 TPS without)&lt;/li&gt;
&lt;li&gt;Guarantees “in-order” delivery and “exactly-once” processing&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;configuration-options&quot;&gt;Configuration options&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Visibility Timeout&lt;/strong&gt; (default 30s, min 0, max 12hrs): if a consumer receives a message from the queue, that message is made invisible to other consumers as long as the Visibility Timeout option specifies. This is done to prevent other consumers to pick up the same message again and give some time to the current process to complete the processing and delete the message. If the current consumer crashes before removing the message, once the Visibility Timeout expires, another consumer will be able to pick up the message again.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Delay Seconds&lt;/strong&gt; (default 0, min 0, max 15min): allows to postpone the delivery of a message. Once added to the queue, a message will remain invisible to consumers for the amount of seconds specified in the Delay Seconds attribute. This attribute can be specified globally at the queue level (in this case the queue is referred as Delay Queue) or at the message level.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Delay queues are similar to visibility timeouts because both features make messages unavailable to consumers for a specific period of time. The difference between the two is that, for delay queues, a message is hidden when it is first added to queue, whereas for visibility timeouts a message is hidden only after it is consumed from the queue&lt;/p&gt;
&lt;h4 id=&quot;long-polling&quot;&gt;Long polling&lt;/h4&gt;
&lt;p&gt;Long polling helps reduce the cost of using Amazon SQS by eliminating the number of empty responses (when there are no messages available for a &lt;code&gt;ReceiveMessage&lt;/code&gt; request). By default, Amazon SQS uses short polling, to enable Long polling you have to specify a positive value for the &lt;code&gt;WaitTimeSeconds&lt;/code&gt; attribute in the &lt;code&gt;ReceiveMessage&lt;/code&gt; request.&lt;/p&gt;
&lt;h4 id=&quot;defaults&quot;&gt;Defaults&lt;/h4&gt;
&lt;p&gt;Messages Max retention (14 days).&lt;/p&gt;
&lt;h3 id=&quot;ec2--ebs--elb--ecs&quot;&gt;EC2 / EBS / ELB / ECS&lt;/h3&gt;
&lt;p&gt;Compute solutions (virtual servers, etc.).&lt;/p&gt;
&lt;h4 id=&quot;types-of-virtual-machines-images-ami&quot;&gt;Types of virtual machines images (AMI)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HVM&lt;/strong&gt; (hardware virtual machine): fully virtualised hardware and boot. Recommended for best performance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PV&lt;/strong&gt; (paravirtual): uses a special boot loader, can run on hardware that does not have direct support for virtualisation. Recommended for old generation instances.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;metadata-api&quot;&gt;Metadata API&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Prefer instance attached roles and metadata API rather than having dedicated access keys saved into every machine&lt;/li&gt;
&lt;li&gt;Public IP is not managed through metadata API (read only)&lt;/li&gt;
&lt;li&gt;Metadata API is available at the following endpoint &lt;code&gt;http://169.254.169.254/latest/meta-data/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;dedicated-hosting&quot;&gt;Dedicated hosting&lt;/h4&gt;
&lt;p&gt;An Amazon EC2 Dedicated Host is a physical server with EC2 instance capacity fully dedicated to your use. Dedicated Hosts can help you address compliance requirements and reduce costs by allowing you to use your existing server-bound software licenses.
There are 2 different dedicated hosting modes (tenancy):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dedicated Hosts&lt;/strong&gt;: gives you additional visibility and control over how instances are placed on a physical server, and you can consistently deploy your instances to the same physical server over time. As a result, Dedicated Hosts enable you to use your existing server-bound software licenses and address corporate compliance and regulatory requirements.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dedicated instances&lt;/strong&gt;: less configurable (no host billing, no visibility of sockets and cores, can’t add capacity).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can change the tenancy of Dedicated instances from “dedicated” to “host”. After you’ve stopped your Dedicated instances, you can change the tenancy to “host” using the &lt;code&gt;ModifyInstancePlacement&lt;/code&gt; API or the AWS Management Console.&lt;/p&gt;
&lt;h4 id=&quot;ebs-backups-and-snapshots&quot;&gt;EBS backups and snapshots&lt;/h4&gt;
&lt;p&gt;You can back up the data on your Amazon EBS volumes to Amazon S3 by taking point-in-time snapshots. Snapshots are incremental backups, which means that only the blocks on the device that have changed after your most recent snapshot are saved. This minimizes the time required to create the snapshot and saves on storage costs by not duplicating data.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A snapshot is &lt;strong&gt;constrained to the region&lt;/strong&gt; where it was created. After you create a snapshot of an EBS volume, you can use it to create new volumes in the same region. You can also &lt;strong&gt;copy snapshots across regions&lt;/strong&gt;, making it possible to use multiple regions for geographical expansion, data center migration, and disaster recovery.&lt;/li&gt;
&lt;li&gt;While snapshots are per region, volumes created from snapshots are tied to only a given availability zone in that region, so EBS Volumes cannot be attached to an EC2 instance in another AZ.&lt;/li&gt;
&lt;li&gt;To take &lt;strong&gt;application consistent snapshots&lt;/strong&gt;: Shut down the EC2 instance and detach the EBS volume, then take the snapshot.&lt;/li&gt;
&lt;li&gt;The most resilient way to backup EBS disks is to take regular snapshots.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;ebs-encryption&quot;&gt;EBS encryption:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Snapshots of encrypted volumes are automatically encrypted.&lt;/li&gt;
&lt;li&gt;Volumes that are created from encrypted snapshots are automatically encrypted.&lt;/li&gt;
&lt;li&gt;When you copy an unencrypted snapshot that you own, you can encrypt it during the copy process.&lt;/li&gt;
&lt;li&gt;When you copy an encrypted snapshot that you own, you can re-encrypt it with a different key during the copy process.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;other-1&quot;&gt;Other:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Cannot use pre-existing MS Windows licenses&lt;/li&gt;
&lt;li&gt;Important things when selecting an instance: I/O and memory requirements.&lt;/li&gt;
&lt;li&gt;ELB: AWS CloudTrail can be enabled to record Application Load Balancer API calls for your account and deliver log files&lt;/li&gt;
&lt;li&gt;To create EC2 instances using the VMDK files you can use the VM Import/Export service&lt;/li&gt;
&lt;li&gt;Placement groups cannot be extended across availability zones&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;limits--defaults--sla&quot;&gt;Limits / Defaults / SLA&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Uptime SLA for Amazon EC2 and EBS within a given region is 99,95%&lt;/li&gt;
&lt;li&gt;Maximum number of VMWare VMs that can be migrated concurrently is 50&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;ecs&quot;&gt;ECS&lt;/h4&gt;
&lt;p&gt;AWS Containers Service.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;With ECS tasks, you can specify an IAM role that can be used by the containers in a task. This is a more fine-grained and secure way to handle permissions at container level rather than at instance level.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;dynamo-db&quot;&gt;Dynamo DB&lt;/h3&gt;
&lt;p&gt;AWS NoSQL database.&lt;/p&gt;
&lt;h4 id=&quot;provisioned-throughput&quot;&gt;Provisioned Throughput&lt;/h4&gt;
&lt;p&gt;When you create a table or index in Amazon DynamoDB, you must specify your capacity requirements for read and write activity. By defining your throughput capacity in advance, DynamoDB can reserve the necessary resources to meet the read and write activity your application requires, while ensuring consistent, low-latency performance.&lt;/p&gt;
&lt;p&gt;You specify throughput capacity in terms of &lt;strong&gt;read capacity units&lt;/strong&gt; and &lt;strong&gt;write capacity units&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One &lt;strong&gt;read capacity unit&lt;/strong&gt; represents one strongly consistent read per second, or two eventually consistent reads per second (you can read twice as much if you opt for an eventually consistent read), for an item up to 4 KB in size. If you need to read an item that is larger than 4 KB, DynamoDB will need to consume additional read capacity units. The total number of read capacity units required depends on the item size, and whether you want an eventually consistent or strongly consistent read.&lt;/li&gt;
&lt;li&gt;One &lt;strong&gt;write capacity unit&lt;/strong&gt; represents one write per second for an item up to 1 KB in size. If you need to write an item that is larger than 1 KB, DynamoDB will need to consume additional write capacity units. The total number of write capacity units required depends on the item size.&lt;/li&gt;
&lt;/ul&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Operation&lt;/th&gt;&lt;th align=&quot;right&quot;&gt;Capacity Unit Size&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;READ&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;4 KB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;READ (eventually consistent)&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;8 KB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WRITE&lt;/td&gt;&lt;td align=&quot;right&quot;&gt;1 KB&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;For example, suppose that you create a table with 5 read capacity units and 5 write capacity units. With these settings, your application could:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Perform strongly consistent reads of up to 20 KB per second (4 KB × 5 read capacity units).&lt;/li&gt;
&lt;li&gt;Perform eventually consistent reads of up to 40 KB per second (8 KB × 5 read capacity units, twice as much read throughput).&lt;/li&gt;
&lt;li&gt;Write up to 5 KB per second (1 KB × 5 write capacity units).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you exceed your allocated capacity your will get a &lt;code&gt;400 Bad Request&lt;/code&gt; response (HTTP API) or a &lt;code&gt;ProvisionedThroughputExceededException&lt;/code&gt; (SDK). The SDK can offer automatic retry with exponential backoff.&lt;/p&gt;
&lt;h4 id=&quot;limits&quot;&gt;Limits&lt;/h4&gt;
&lt;p&gt;The cumulative size of attributes per item must fit within the maximum DynamoDB item size (400 KB).&lt;/p&gt;
&lt;h3 id=&quot;redshift&quot;&gt;Redshift&lt;/h3&gt;
&lt;p&gt;AWS analytics database (columnar data storage).&lt;/p&gt;
&lt;p&gt;To be able to export data into an S3 bucket from a Redshift instance in a private VPC and make sure data doesn’t leave VPC:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enable Amazon Redshift Enhanced VPC routing&lt;/li&gt;
&lt;li&gt;Create and configure an Amazon S3 VPC endpoint&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;rds&quot;&gt;RDS&lt;/h3&gt;
&lt;p&gt;AWS Relational Database System. Allows to easily deploy single-machine or distributed instances of the most common databases (Oracle, SQL Server, MySQL, MariaDB, PostgreSQL) and Amazon’s own distributed relational database “Aurora”.&lt;/p&gt;
&lt;h4 id=&quot;replication&quot;&gt;Replication&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Read replica replication is asynchronous&lt;/li&gt;
&lt;li&gt;Replicas across AZs are synchronous&lt;/li&gt;
&lt;li&gt;Read replicas are good for heavy queries (e.g. analytical queries for back office operations)&lt;/li&gt;
&lt;li&gt;Read replica is supported for MySQL, MariaDB, and PostgreSQL as well as Amazon Aurora&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;encryption&quot;&gt;Encryption&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;To migrate an unencrypted DB to an encrypted one: create a new DB Instance with encryption enabled and then manually migrate your data into it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;automatic-failover-of-multi-az-deployments&quot;&gt;Automatic failover of Multi AZ deployments&lt;/h4&gt;
&lt;p&gt;Events that would cause Amazon RDS to initiate a failover to the standby replica:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An Availability Zone outage&lt;/li&gt;
&lt;li&gt;The primary DB instance fails&lt;/li&gt;
&lt;li&gt;The DB instance’s server type is changed&lt;/li&gt;
&lt;li&gt;The operating system of the DB instance is undergoing software patching&lt;/li&gt;
&lt;li&gt;A manual failover of the DB instance was initiated using Reboot with failover&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;limits-1&quot;&gt;Limits&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Maximum retention period for automated backup: 35 days&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;other-2&quot;&gt;Other&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Amazon RDS enables automated backups settings depends on the DB engine selected&lt;/li&gt;
&lt;li&gt;RDS Provisioned IOPS (SSD) Storage is preferable for high-performance OLTP workloads&lt;/li&gt;
&lt;li&gt;default metrics for RDS: The number of current connections to the database&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;vpc&quot;&gt;VPC&lt;/h3&gt;
&lt;p&gt;Amazon Virtual Private Cloud. Allows you to create complex private networks in the cloud.&lt;/p&gt;
&lt;h4 id=&quot;availability-zones-names&quot;&gt;Availability zones names&lt;/h4&gt;
&lt;p&gt;Availability Zones consist of one or more discrete data centers. Every account has references to availability zones per regions shuffled. As such, ‘eu-west-1b’ for instance, is not necessarily the same physical location for ‘eu-west-1b’ in another account (important in some latency related questions).&lt;/p&gt;
&lt;h4 id=&quot;how-to-enable-site-to-site-vpn&quot;&gt;How to enable site to site VPN:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Hardware VPN enabled on VPC&lt;/li&gt;
&lt;li&gt;On premise customer gateway&lt;/li&gt;
&lt;li&gt;Virtual private gateway
&lt;ul&gt;
&lt;li&gt;Peering connections do not support Edge to Edge&lt;/li&gt;
&lt;li&gt;Default of 5 elastic IPs per region&lt;/li&gt;
&lt;li&gt;To enable network access logging you can:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Make use of an OS level logging tools such as iptables and log events to CloudWatch or S3.&lt;/li&gt;
&lt;li&gt;Set up a Flow Log for the group of instances and forward them to CloudWatch&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can use a network address translation (NAT) gateway to enable instances in a private subnet to connect to the internet or other AWS services, but prevent the internet from initiating a connection with those instances&lt;/p&gt;
&lt;p&gt;5 elastic IPS/region max by default&lt;/p&gt;
&lt;h3 id=&quot;cloudwatch&quot;&gt;Cloudwatch&lt;/h3&gt;
&lt;p&gt;Service that allows you to collect metrics, logs and monitor all the other provisioned services (EC2, Load Balancers, etc). It also allows you to create dashboards and manage alerts.&lt;/p&gt;
&lt;h4 id=&quot;defaults-1&quot;&gt;Defaults&lt;/h4&gt;
&lt;p&gt;Metrics retention for a deleted EC2 (15 months)&lt;/p&gt;
&lt;h3 id=&quot;cloudfront&quot;&gt;Cloudfront&lt;/h3&gt;
&lt;p&gt;AWS content delivery network.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Can support multi-language resources or other variation of resources using query string parameters by setting cache based on all (or some) queries bring parameters (e.g. &lt;code&gt;http://d111111abcdef8.cloudfront.net/main.html?language=fr&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;There is a cost when clearing cache (path invalidation): first 1,000 paths requested for invalidation each month are FREE. Thereafter, $0.005 per path requested for invalidation&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;swf&quot;&gt;SWF&lt;/h3&gt;
&lt;p&gt;Simple Workflow Service, allows to define and run background workflow composed by parallel or sequential steps. Also described as a &lt;em&gt;fully-managed state tracker and task coordinator&lt;/em&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Preferred to SQS with cases like order management where there might be manual steps (eg. packing and shipping a parcel) or message delivery needs to be more reliable (only once &amp;#x26; in order).&lt;/li&gt;
&lt;li&gt;When a workflow is not making progress is probably because of a missing manual interaction.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;closing-off&quot;&gt;Closing off&lt;/h2&gt;
&lt;p&gt;This is all I have for you. Again this is not comprehensive (E.g. I didn’t have notes for services like Lambda or SNS), so please don’t rely exclusively on this (and if you do don’t hold me responsible 😜).&lt;/p&gt;
&lt;p&gt;At this point let me just wish you “Good luck” and let me know how it goes.&lt;/p&gt;
&lt;p&gt;A huge thanks goes to &lt;a href=&quot;https://twitter.com/Podgeypoos79&quot;&gt;Padraig O’Brien&lt;/a&gt; and &lt;a href=&quot;https://vectra.ai&quot;&gt;Vectra.ai&lt;/a&gt; for supporting this achievement! 🙏&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/aws-solution-architect-associate-exam-notes-tips.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/aws-solution-architect-associate-exam-notes-tips.png" width="1200" height="630"/></media:content><category>aws</category><author>Luciano Mammino</author><comments>https://loige.co/aws-solution-architect-associate-exam-notes-tips/#comments</comments><enclosure url="https://loige.co/og/aws-solution-architect-associate-exam-notes-tips.png" length="0" type="image/png"/></item><item><title>2018 - A year in review</title><link>https://loige.co/2018-a-year-in-review/</link><guid isPermaLink="true">https://loige.co/2018-a-year-in-review/</guid><description>A personal 2018 year in review including achievements like migrating my blog to a serverless setup, 8 conference talks, career growth at Vectra, open source contributions, and reflections on side projects. Outlines goals for 2019 like writing more, releasing middy 1.0, and getting advanced AWS certifications.</description><pubDate>Sun, 20 Jan 2019 02:18:58 GMT</pubDate><content:encoded>&lt;p&gt;It is that time of the year when I have to look back at the previous year and see what were my achievements, my failures and set my expectations for my 2019.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Full disclosure&lt;/strong&gt;: I write this type of posts mostly for myself, so I expect this to be
boring to death and most likely useless for everyone else.&lt;/p&gt;
&lt;p&gt;You have been warned, read at your own risk!&lt;/p&gt;
&lt;h2 id=&quot;static-blog-migration&quot;&gt;Static blog migration&lt;/h2&gt;
&lt;p&gt;Interesting achievement of the last year is that I finally migrated this blog from Ghost to a static setup using totally free and Open Source tools, which costs me &lt;strong&gt;0.00 $ per month&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I am using &lt;a href=&quot;https://www.gatsbyjs.org&quot;&gt;GatsbyJS&lt;/a&gt; as the engine for the static website.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;GatsbyJS logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;600&quot; height=&quot;300&quot; src=&quot;https://loige.co/_astro/gatsbyjs-logo.BtdxadbX_Z2rin1o.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;If you are curious to see my setup (and maybe even correct typos in my articles), I have everything open sourced at
&lt;a href=&quot;https://github.com/lmammino/loige.co&quot;&gt;lmammino/loige.co&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I don’t think my GatsbyJS config is particularly interesting, but the entire publishing pipeline might be worth some words.&lt;/p&gt;
&lt;p&gt;As per January 2019, this blog is published on &lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub pages&lt;/a&gt; using the &lt;a href=&quot;https://github.com/lmammino/loige.co/tree/gh-pages&quot;&gt;gh-pages branch&lt;/a&gt; which I publish using the very handy &lt;a href=&quot;http://npm.im/gh-pages&quot;&gt;&lt;code&gt;gh-pages&lt;/code&gt; package&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The static website is served through &lt;a href=&quot;https://www.cloudflare.com/cdn&quot;&gt;Cloudflare CDN&lt;/a&gt;, which takes care of speeding up the delivery across the globe and other handy things like making sure the website runs on &lt;code&gt;https&lt;/code&gt; correctly.&lt;/p&gt;
&lt;p&gt;Every time I push on master, a &lt;a href=&quot;https://circleci.com&quot;&gt;CirlceCI&lt;/a&gt; build is triggered, and, if the build succeeds, a new version of the website is published automatically.&lt;/p&gt;
&lt;p&gt;Checkout my &lt;a href=&quot;https://github.com/lmammino/loige.co/blob/master/.circleci/config.yml&quot;&gt;CircleCI config&lt;/a&gt; if you want to do something similar.&lt;/p&gt;
&lt;p&gt;I wanted to do something like this for a while, so being able to achieve this was a big win for me!&lt;/p&gt;
&lt;h2 id=&quot;conference-talks&quot;&gt;Conference talks&lt;/h2&gt;
&lt;p&gt;Pretty much like in the last 2 years, I tried to invest some of my time in engaging with the community through conference talks.&lt;/p&gt;
&lt;p&gt;This year wasn’t my best, but I still managed to deliver 8 talks and a workshop around the world. For the first time I delivered one outside Europe in the amazing New York.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Luciano Mammino at FullStack London&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;683&quot; src=&quot;https://loige.co/_astro/luciano-mammino-fullstack-london.DETs5McH_SqO1O.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Here’s the full list of talks for 2018, you can find more details in the usual &lt;a href=&quot;https://loige.co/speaking/&quot;&gt;speaking section&lt;/a&gt; with links to slides and videos when available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“&lt;em&gt;Getting started with Serverless and Lambda Functions&lt;/em&gt;” (workshop), Codemotion Rome (April)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;Unbundling the JavaScript module bundler&lt;/em&gt;”, Codemotion Rome (April)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;The future will be Serverless&lt;/em&gt;”, JS Day Verona (May)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;Cracking JWT tokens: a tale of magic, Node.JS and parallel computing&lt;/em&gt;”, Web Rebels Oslo (June)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;Cracking JWT tokens: a tale of magic, Node.JS and parallel computing&lt;/em&gt;”, Buzz JS New York (June)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;Unbundling the JavaScript module bundler&lt;/em&gt;”, Dublin JS (July)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;Cracking JWT tokens: a tale of magic, Node.JS and parallel computing&lt;/em&gt;”, FullStack London (July)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;Unbundling the JavaScript module bundler&lt;/em&gt;”, Øredev Malmo (November)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;Processing TeraBytes of data every day and sleeping at night&lt;/em&gt;”, Codemotion Milan (November)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Compared to 2017, when I presented 17 talks/workshops, this is a -52.94% “growth” rate. Ouch! 😵&lt;/p&gt;
&lt;p&gt;In reality, I don’t mind at all this level of commitment for conferences and workshops and I’ll try to keep
2019 to a similar rate to 2018 and not overcommit.&lt;/p&gt;
&lt;h2 id=&quot;career&quot;&gt;Career&lt;/h2&gt;
&lt;p&gt;From a career perspective I spent my 2018 at Vectra, where I worked “&lt;em&gt;automating the hunt for cyberattackers and speeding-up incident response&lt;/em&gt;”, which essentially means building software that help companies to identify cyber attacks and resolve them as quick as possible and with the least amount of effort.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Vectra Cognito Platform against Cyber Attackers&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;800&quot; height=&quot;796&quot; src=&quot;https://loige.co/_astro/vectra-cognito-stop-cyber-attackers.C_oogPhB_ZMYCyX.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;One year at Vectra has been a blast and I had the pleasure (and luck 🍀) to be able to contribute to some important success stories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I was involved in bootstrapping and scaling up a new European site that started from 3 and now counts 20+ people (engineering and sales). All world-class professionals with whom I love to work and from whom I can learn a lot every day.&lt;/li&gt;
&lt;li&gt;Built a new product line from scratch. The product is already making revenue! This is a quite complicated product that is able to ingest and make searchable &lt;a href=&quot;https://loige.link/terabytes&quot;&gt;Terabytes of data every day&lt;/a&gt;!&lt;/li&gt;
&lt;li&gt;Witnessed an astounding &lt;a href=&quot;https://www.vectra.ai/news/vectra-announces-104-growth-in-annual-recurring-revenue-during-2018&quot;&gt;104% growth in annual recurring revenue&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One year in the making, there was no shortage of personal skills development:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Improved my knowledge of &lt;strong&gt;AWS&lt;/strong&gt;, including &lt;a href=&quot;https://loige.co/aws-solution-architect-associate-exam-notes-tips&quot;&gt;getting certificated as Solution Architect&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Improved my knowledge of several technologies I love: &lt;strong&gt;Terraform&lt;/strong&gt;, &lt;strong&gt;Ansible&lt;/strong&gt;, &lt;strong&gt;Packer&lt;/strong&gt;, &lt;strong&gt;ElasticSearch&lt;/strong&gt;, &lt;strong&gt;Node.js&lt;/strong&gt;, &lt;strong&gt;JavaScript&lt;/strong&gt;, &lt;strong&gt;Python&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Got some new interesting use cases for &lt;strong&gt;Serverless architectures&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Started to acquire totally new skills like &lt;strong&gt;GoLang&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Deep dived into binary protocols like &lt;strong&gt;Capnp&lt;/strong&gt; and got much better understanding of some low level mechanics like &lt;strong&gt;serialization&lt;/strong&gt; and &lt;strong&gt;memory management&lt;/strong&gt; (thank you &lt;a href=&quot;https://twitter.com/gbinside&quot;&gt;@gbinside&lt;/a&gt; for your forbearing mentorship on this).&lt;/li&gt;
&lt;li&gt;Worked a lot on &lt;strong&gt;Node.js performance optimizations&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Learned a bit about &lt;strong&gt;network security&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Been exposed to some high level &lt;strong&gt;AI/ML&lt;/strong&gt; concepts.&lt;/li&gt;
&lt;li&gt;I have been a team leader and an architect, which meant that I had to engage a lot with peers and customers which probably improved some soft skills: &lt;strong&gt;empathy&lt;/strong&gt;, &lt;strong&gt;communication&lt;/strong&gt;, &lt;strong&gt;teamwork&lt;/strong&gt;, &lt;strong&gt;patience&lt;/strong&gt;, &lt;strong&gt;accountability&lt;/strong&gt;, etc (I hope I also improved my english in the process 😅).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With this premise, I expect my 2019 at Vectra to be even more exciting than 2018. I am sure I’ll learn and grow a ton.&lt;/p&gt;
&lt;p&gt;There is a lot of work to do to keep the current growth rate, and I’ll do my best to do my part!&lt;/p&gt;
&lt;h2 id=&quot;side-projects&quot;&gt;Side projects&lt;/h2&gt;
&lt;p&gt;In 2017, I launched and contributed to a number of interesting side projects.
In 2018, I didn’t launch any new one, but I tried to take care at best of the
projects launched in the previous year, so I am going to recap here what happened with each one of them.&lt;/p&gt;
&lt;h3 id=&quot;fullstack-bulletin&quot;&gt;Fullstack bulletin&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://fullstackbulletin.com&quot;&gt;FullStack Bulletin&lt;/a&gt;, a newsletter for ambitious FullStack developers, has been ongoing in 2018 with the same format of 2017 except some minor improvement. It recently surpassed 1000 subscribers, all through organic growth.&lt;/p&gt;
&lt;p&gt;This projejcts takes me 30-60 minutes of work every week, but I am happy to keep investing the time as it works for me as well to stay up to date with the latest FullStack trends.&lt;/p&gt;
&lt;p&gt;I still plan to invest on it during 2019 and maybe try to improve the format (new layout, new books, new quotes, etc.).&lt;/p&gt;
&lt;h3 id=&quot;serverless-lab&quot;&gt;Serverless lab&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://serverlesslab.com&quot;&gt;Serverless Lab&lt;/a&gt; is a side-project started by &lt;a href=&quot;https://twitter.com/podgeypoos79&quot;&gt;Padraig “Podge” O’Brien&lt;/a&gt; and myself to help companies to get started quickly with serverless technologies on AWS.&lt;/p&gt;
&lt;p&gt;During 2018, we took a chance to improve and update our material, but we used it for only one workshop.&lt;/p&gt;
&lt;p&gt;It really takes a lot of time to find interested crowds. So far, all the engagement was mostly organic.&lt;/p&gt;
&lt;p&gt;I am not sure yet how much I will commit on this project in 2019. I’ll try to see if there’s interest in the market.&lt;/p&gt;
&lt;h3 id=&quot;middy&quot;&gt;Middy&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://middy.js.org&quot;&gt;Middy&lt;/a&gt; is a &lt;em&gt;Node.js middleware engine for AWS Lambda&lt;/em&gt;. It basically allows you to take care of tedious and repetitive tasks such as validation, input deserialization and output serialization by encapsulating this external logic into reusable and testable middlewares.&lt;/p&gt;
&lt;p&gt;In 2018 middy had a decent success. Here some numbers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;almost 500 stars on Github&lt;/li&gt;
&lt;li&gt;an average of 6.000 downloads a week&lt;/li&gt;
&lt;li&gt;31 contributors over 124 releases.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I am quite proud of this project, even though in the latest months I felt like I didn’t have the time, neither the energies to properly take care of it. My response time has become unacceptable and open PRs and Issues have been accumulating. I am a bit worried that the project will start to drift away.&lt;/p&gt;
&lt;p&gt;I recently &lt;a href=&quot;https://github.com/middyjs/middy/issues/263&quot;&gt;asked more support to the other contributors&lt;/a&gt;, basically stepping away from being the main maintainer.&lt;/p&gt;
&lt;p&gt;I have to thank you some people for being there and trying their best to support the project:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/theburningmonk&quot;&gt;Yan Cui&lt;/a&gt; (who also wrote &lt;a href=&quot;https://epsagon.com/blog/enforce-consistent-error-handling-in-aws-lambda-with-wrappers/&quot;&gt;an amazing article that mentions middy&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/vladholubiev&quot;&gt;Vlad Holubiev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/DavidWells&quot;&gt;David Wells&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And all the other contributors.&lt;/p&gt;
&lt;p&gt;A stable version for the 1.0.0 branch has not been released yet. I’ll try to focus on getting it done in 2019 and to try to be a little bit more responsive in replying to PRs and issues.&lt;/p&gt;
&lt;p&gt;Meanwhile I hope new people will be able to jump on board and support the project.&lt;/p&gt;
&lt;h3 id=&quot;fastify&quot;&gt;Fastify&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.fastify.io&quot;&gt;Fastify&lt;/a&gt;, started by &lt;a href=&quot;https://twitter.com/delvedor&quot;&gt;
Tomas Della Vedova&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/matteocollina&quot;&gt;Matteo Collina&lt;/a&gt; is a &lt;strong&gt;fast and low overhead web framework for Node.js&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I have been marginally contributing to this fantastic project, taking care of setting up the official website (including the docs) and its automated pipeline.&lt;/p&gt;
&lt;p&gt;In 2018, I did some minor improvements, but nothing major.&lt;/p&gt;
&lt;p&gt;I admire all the contributors to the project as they managed to invest an incredible amount of energies in the project and attracted a pool of very talented people creating a strong community of users.&lt;/p&gt;
&lt;p&gt;I am glad and grateful that I am being considered one of the core team members, even though I am very far away from putting the same amount of energy that the other contributors do.&lt;/p&gt;
&lt;p&gt;I want to narrow my focus in 2019 so I don’t have any special plan to contribute more to Fastify in 2019, but I’ll try to be available to give my support on improving the website where needed.&lt;/p&gt;
&lt;h2 id=&quot;blog-posts&quot;&gt;Blog posts&lt;/h2&gt;
&lt;p&gt;In 2018 I wasn’t a very active author… So I’ll go straight to the list of new posts published in this blog during the year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/aws-command-line-s3-content-from-stdin-or-to-stdout&quot;&gt;AWS Command line: S3 content from stdin or to stdout&lt;/a&gt; (~7.800 views)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/aws-solution-architect-associate-exam-notes-tips&quot;&gt;AWS Solution Architect Associate exam, my notes and tips&lt;/a&gt; (~5.800 views)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/emerging-javascript-pattern-multiple-return-values&quot;&gt;Emerging JavaScript pattern: multiple return values&lt;/a&gt; (~3.200 views)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/random-emoji-in-your-prompt-how-and-why&quot;&gt;A random emoji in your terminal prompt. How and Why!&lt;/a&gt; (~1.500 views)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s interesting to see that there’s still a lot of the traffic driven by old (and maybe outdated) articles from the previous years like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/extracting-data-from-wikipedia-using-curl-grep-cut-and-other-bash-commands&quot;&gt;Extracting data from Wikipedia using curl, grep, cut and other shell commands&lt;/a&gt; (~7.300 views)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/using-lets-encrypt-and-certbot-to-automate-the-creation-of-certificates-for-openvpn&quot;&gt;Using Let’s Encrypt and Certbot to automate the creation of certificates for OpenVPN
&lt;/a&gt; (~7.200 views)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/developing-a-web-application-with-lumen-and-mysql&quot;&gt;Developing a web application with Lumen and MySql&lt;/a&gt; (~7.000 views)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/gulp-and-ftp-update-a-website-on-the-fly&quot;&gt;Gulp and FTP: update a website “on the fly”&lt;/a&gt; (~4.000 views).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The total number of page views amounts to about 65.000 views, which compared to the previous year total of 57.000 is a slight increase of 14.04%!&lt;/p&gt;
&lt;p&gt;I guess I have to write more and find more interesting topics if I want to keep this blog relevant in 2019! Also I should probably focus more on one or two topics, rather then writing about random fun stuff that comes into my mind!&lt;/p&gt;
&lt;h2 id=&quot;external-posts&quot;&gt;External posts&lt;/h2&gt;
&lt;p&gt;Aside from the articles published on my blog I had the pleasure to collaborate with Avanscoperta and &lt;a href=&quot;https://twitter.com/gojkoadzic&quot;&gt;Gojko Adzic&lt;/a&gt; writing an interview from the title “&lt;a href=&quot;https://blog.avanscoperta.it/it/2018/08/31/is-serverless-the-future-of-cloud-computing&quot;&gt;Is Serverless the future of Cloud Computing?&lt;/a&gt;”.&lt;/p&gt;
&lt;p&gt;It’s always fun and rewarding to write guest posts and it’s a nice way to get my name out from my common channels.&lt;/p&gt;
&lt;p&gt;I guess in 2019 I should keep doing that and maybe build some new relationship with other publishers :)&lt;/p&gt;
&lt;h2 id=&quot;open-sourcing&quot;&gt;Open Sourcing&lt;/h2&gt;
&lt;p&gt;In 2018, I kept spending some time working out some small open source contributions. Here’s a quick list of my main GitHub contributions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/fib-it&quot;&gt;lmammino/fib-it&lt;/a&gt;: 6 ways to generate a fibonacci sequence in JavaScript.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/twaffle&quot;&gt;lmammino/twaffle&lt;/a&gt;: A TWitter rAFFLE script.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/get-poop-done&quot;&gt;lmammino/get-poop-done&lt;/a&gt;: A crappy-but-lovely™ todo list app.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/invok&quot;&gt;lmammino/invok&lt;/a&gt;: Command line tool to Invoke Go lambda functions locally.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/salesforce/ja3&quot;&gt;salesforce/ja3&lt;/a&gt; (contribution): JA3 is a standard for creating SSL client fingerprints in an easy to produce and shareable way.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/felixhageloh/uebersicht&quot;&gt;felixhageloh/uebersicht&lt;/a&gt; (contribution): Keep an eye on what’s happening on your machine and in the world.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/gatsbyjs/gatsby&quot;&gt;gatsbyjs/gatsby&lt;/a&gt; (contribution): Build blazing fast, modern apps and websites with React.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tj/node-blocked&quot;&gt;tj/node-blocked&lt;/a&gt; (contribution): Check if the Node.js event loop is blocked.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/capnp-stream&quot;&gt;lmammino/capnp-stream&lt;/a&gt;: A Node.js readable stream for Cap’n Proto encoded binary input.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fastify/fastify-http-proxy&quot;&gt;fastify/fastify-http-proxy&lt;/a&gt; (contribution): Proxy your http requests to another server, with hooks.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/benchmark-distributed-jwt-cracker&quot;&gt;lmammino/benchmark-distributed-jwt-cracker&lt;/a&gt;: A benchmark suite using AWS for distributed-jwt-cracker.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/metrica&quot;&gt;lmammino/metrica&lt;/a&gt;: Event Emitter based node library that emits process metrics (uptime, memory, cpu) at given intervals.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/zeek/zeek&quot;&gt;zeek/zeek&lt;/a&gt; (contribution): Zeek (formerly known as Bro) is a powerful network analysis framework that is much different from the typical IDS you may know.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/lambda-runtime-node8-capnp&quot;&gt;lmammino/lambda-runtime-node8-capnp&lt;/a&gt;: Docker container image that resembles AWS lambda runtime for Node.js 8.10 and CapnProto 0.6.1&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/lambda-runtime-node8&quot;&gt;lmammino/lambda-runtime-node8&lt;/a&gt;: Docker container image that resembles AWS lambda runtime for Node.js 8.10.0&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/openssl-rfc-mapping&quot;&gt;lmammino/openssl-rfc-mapping&lt;/a&gt;: A quick’n’dirty script to map OpenSSL RFC to machine parseable data.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/stream-accumulator&quot;&gt;lmammino/stream-accumulator&lt;/a&gt;: Accumulate all the data flowing through a stream and emit it as a single chunk or as a promise.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/maxogden/mississippi&quot;&gt;maxogden/mississippi&lt;/a&gt; (contribution): A collection of useful stream utility modules for writing better code using streams.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/lumpy&quot;&gt;lmammino/lumpy&lt;/a&gt;: A lumpy and dummy JavaScript module bundler for those who are stuck in the past.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/tick-stream&quot;&gt;lmammino/tick-stream&lt;/a&gt;: A simple transform stream that can log a tick every time data is pushed through a pipe.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nickjj/ansible-docker&quot;&gt;nickjj/ansible-docker&lt;/a&gt; (contribution): Install / Configure Docker and Docker Compose using Ansible.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jsdoc2md/dmd&quot;&gt;jsdoc2md/dmd&lt;/a&gt; (contribution): The default output template for jsdoc2md.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;👍 Comparing last year (19) to this year (22) I had a +15.79% repo contributions increase. Another pretty good vanity metric!&lt;/p&gt;
&lt;h2 id=&quot;previous-years-goals&quot;&gt;Previous years goals&lt;/h2&gt;
&lt;p&gt;Now it’s time to check whether I met &lt;a href=&quot;https://loige.co/2017-a-year-in-review#expectations-for-next-year&quot;&gt;the goals I set last year&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;MOAR conference talks/workshops (at least 8)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;😭 &lt;strong&gt;Write at least 8 quality blog posts (excluding this one!)&lt;/strong&gt;: did only 5!&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;Learn a lot about Security, Machine Learning and networking&lt;/strong&gt;: I guess I learned a bit, but probably not as much as I was expecting last year.&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;Keep contributing to Fastify&lt;/strong&gt;: didn’t do a lot.&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;Keep working on Middy&lt;/strong&gt;: Initially well, lately not so much…&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Move my blog to a static publishing engine and (possibly) use a serverless hosting approach&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;Learn enough about Rust and build something with it&lt;/strong&gt;: studied for a while, but didn’t really build anything. I feel I kind of dropped it in favor of GoLang.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Learn enough about Elastic Search and build something with it&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;Learn enough about Kubernetes and build something with it&lt;/strong&gt;: Again, studied a bit but didn’t really do much with it.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Do stuff with CSS Grids and Flexbox&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Keep learning AWS and serverless&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;More serious and constant BJJ training&lt;/strong&gt;: kept training, but I should probably be more serious about it!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;expectations-for-next-year&quot;&gt;Expectations for next year&lt;/h2&gt;
&lt;p&gt;Ok, it’s finally time to move to the good intentions for the next year! I have been very long already so I’ll just sort this part out with a simple unordered checklist, I am already looking forward to seeing, in one year time, how many items will be crossed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keep doing conference talks/workshops (at least 8)&lt;/li&gt;
&lt;li&gt;Write at least 8 quality blog posts (excluding this one!)&lt;/li&gt;
&lt;li&gt;Keep learning about Security, Machine Learning and networking&lt;/li&gt;
&lt;li&gt;Release Middy v1.0&lt;/li&gt;
&lt;li&gt;Publish a new book (or a new edition ✌️)&lt;/li&gt;
&lt;li&gt;Get proficient in GoLang&lt;/li&gt;
&lt;li&gt;Learn a bit about Social Media and digital marketing&lt;/li&gt;
&lt;li&gt;Keep learning AWS and serverless&lt;/li&gt;
&lt;li&gt;Get an advanced AWS certification&lt;/li&gt;
&lt;li&gt;Play with new database technologies (e.g. CockroachDB &amp;#x26; Clickhouse)&lt;/li&gt;
&lt;li&gt;Improve FullStack bulletin&lt;/li&gt;
&lt;li&gt;More serious and constant BJJ training!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s all… If you are still reading, either you are a bot 🤖 or you are my new hero 💪!&lt;/p&gt;
&lt;p&gt;In the latter case, I’d really love you to leave a comment here and let me know something about your 2018 and what you envision for your 2019.&lt;/p&gt;
&lt;p&gt;See you in the next post, CIAO!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/2018-a-year-in-review.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/2018-a-year-in-review.png" width="1200" height="630"/></media:content><category>life</category><author>Luciano Mammino</author><comments>https://loige.co/2018-a-year-in-review/#comments</comments><enclosure url="https://loige.co/og/2018-a-year-in-review.png" length="0" type="image/png"/></item><item><title>2019 - A year in review</title><link>https://loige.co/2019-a-year-in-review/</link><guid isPermaLink="true">https://loige.co/2019-a-year-in-review/</guid><description>Luciano Mammino reflects on his 2019 tech career achievements including conference talks, career moves, open source contributions, and blog posts. He also sets realistic goals for 2020 like finding a new job, releasing Middy 1.0, and getting an advanced AWS certification.</description><pubDate>Sat, 25 Jan 2020 14:18:58 GMT</pubDate><content:encoded>&lt;p&gt;A little bit later than I expected over the new year, but here we are again, with my usual introspective post to figure out how the hell did the last year went and how to make the best out of the new year.&lt;/p&gt;
&lt;p&gt;This is going to be boring (again I do this kind of posts selfishly only for myself), so brace yourself if you really want to keep going on this!&lt;/p&gt;
&lt;h2 id=&quot;tech-leadership-training&quot;&gt;Tech Leadership Training&lt;/h2&gt;
&lt;p&gt;Possibly the biggest achievement of last year was my contribution as a teacher to the &lt;a href=&quot;https://www.codemotion.com/learning/tp/tech-leadership-training-program-26&quot;&gt;Tech Leadership Training - Taking you from Developer to CTO&lt;/a&gt; organised by Codemotion and Facebook Developer Circles.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Luciano Mammino Tech Leadership Training with Codemation and Facebook Developer Circles&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1624&quot; height=&quot;838&quot; src=&quot;https://loige.co/_astro/loige-co-luciano-mammino-tech-leadership-training-codemotion-facebook.CnuTZ6Hu_Z1d0tok.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;The course is designed to help developers in their journey to become CTO of startups, combining strong interpersonal and influential skills along with an empathic ear.&lt;/p&gt;
&lt;p&gt;The course was made of 3 modules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Module 1: Defining the CTO Role&lt;/li&gt;
&lt;li&gt;Module 2: AI/Machine Learning&lt;/li&gt;
&lt;li&gt;Module 3: Software Architecture/DevOps&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I presented Module 3, where I essentially covered what happens when a startup scales from thousands of users to millions of users. My track highlights that only a correct and solid software architecture can keep the business safe, but also that lean and agile techniques can allow your product to keep growing over time.&lt;/p&gt;
&lt;h2 id=&quot;conference-talks&quot;&gt;Conference talks&lt;/h2&gt;
&lt;p&gt;I invested a decent amount of time delivering conference talks and I accrued a total of 13 talks and workshops in 6 different countries.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Luciano Mammino talks at AustinJS meetup&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2004&quot; height=&quot;1436&quot; src=&quot;https://loige.co/_astro/luciano-mammino-talk-austin-js-meetup.pyiSNGEv_2pQcb5.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Here’s the full list of talks for 2019, you can find more details in the usual &lt;a href=&quot;https://loige.co/speaking/&quot;&gt;speaking section&lt;/a&gt; with links to slides and videos when available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“&lt;em&gt;Processing TeraBytes of data every day and sleeping at night&lt;/em&gt;”, AWS Usergroup Dublin (February)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;Processing TeraBytes of data every day and sleeping at night&lt;/em&gt;”, AWS Usergroup Belfast (February)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;It’s about time to embrace Streams&lt;/em&gt;”, DublinJS (March)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;It’s about time to embrace Streams&lt;/em&gt;”, Codemotion Rome (March)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;It’s about time to embrace Streams&lt;/em&gt;”, CityJS Conf London (May)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;It’s about time to embrace Streams&lt;/em&gt;”, Node Ukraine (May)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;It’s about time to embrace Streams (workshop)&lt;/em&gt;”, DevIT Thessaloniki (June)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;Unbundling the JavaScript module bundler&lt;/em&gt;”, DevIT Thessaloniki (June)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;Processing TeraBytes of data every day and sleeping at night&lt;/em&gt;”, InfiniteConf London (July)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;It’s about time to embrace Streams&lt;/em&gt;”, Austin Node.js Meetup (August)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;Serverless, the Middy way (workshop)&lt;/em&gt;”, AWS Community Day Dublin (October)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;SERVERLESS Panel – Serverless Insights – Taking Serverless to the next level&lt;/em&gt;”, AWS Community Day Dublin (October)&lt;/li&gt;
&lt;li&gt;“&lt;em&gt;It’s about time to embrace Streams&lt;/em&gt;”, MachJS Meetup Manchester (October)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Compared to 2018, when I presented 8 talks/workshops, this is a 62.5% “growth” rate. 👍&lt;/p&gt;
&lt;p&gt;Not sure how much do I want to commit for this year. I am not actively applying for conferences, so probably I will limit my participation to events where I get a direct invitation. Also, I will have to start developing some new talks!&lt;/p&gt;
&lt;h2 id=&quot;career&quot;&gt;Career&lt;/h2&gt;
&lt;p&gt;From a career perspective, I spent another year at Vectra. As usual, it was an intense and engaging year, full of learnings. Probably most learnings were not as technical as I hoped, but still, I am sure that developing soft skills and business skills is always a precious addition to any technical career.&lt;/p&gt;
&lt;p&gt;Surprise now! Next week is going to be my last week at Vectra. I decided to move on and search for new opportunities starting from February 2020.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/loige&quot;&gt;Hit me up on Twitter&lt;/a&gt; if you think I could be a good fit in your company/project and let’s have a chat!&lt;/p&gt;
&lt;h2 id=&quot;side-projects&quot;&gt;Side projects&lt;/h2&gt;
&lt;p&gt;Nothing new in terms of side projects, but I am still running and contributing to my usual side projects: &lt;a href=&quot;https://fullstackbulletin.com&quot;&gt;FullStack Bulletin&lt;/a&gt;, &lt;a href=&quot;https://serverlesslab.com&quot;&gt;Serverless Lab&lt;/a&gt; and &lt;a href=&quot;https://middy.js.org&quot;&gt;Middy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The work on middy has been a little bit stagnating over the year. Not being able to work on a lot of serverless projects on my day to day made me lost a bit of focus and perspective.&lt;/p&gt;
&lt;p&gt;Thankfully the community around middy has been particularly active and involved and a lot of people helped me driving the project towards the long-awaited 1.0.0 beta. This year we will make 1.0.0 stable and start to make plans for the future of the framework for the next big release.&lt;/p&gt;
&lt;p&gt;A great shout out to &lt;a href=&quot;https://github.com/willfarrell&quot;&gt;Will Farrell&lt;/a&gt; and &lt;a href=&quot;https://github.com/sdomagala&quot;&gt;Sebastian Domagała&lt;/a&gt; for their great contributions and the constant support.&lt;/p&gt;
&lt;p&gt;One interesting thing is that towards the end of the year I started working on a (currently secret) side project, that should be released this year around May or June. Stay tuned 😇&lt;/p&gt;
&lt;h2 id=&quot;blog-posts&quot;&gt;Blog posts&lt;/h2&gt;
&lt;p&gt;In 2019 I wasn’t a very active author… It was actually pretty bad with only 3 blog posts published:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/javascript-iterator-patterns&quot;&gt;JavaScript iterator patterns&lt;/a&gt; (~14.600 views)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/fastify-and-preact-for-quick-web-app-prototyping&quot;&gt;Fastify and Preact for quick web app prototyping&lt;/a&gt; (~4.300 views)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/lean-npm-packages&quot;&gt;Lean NPM packages&lt;/a&gt; (~4.300 views)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s interesting to see that my 2 top posts of last year were articles written during the previous year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/emerging-javascript-pattern-multiple-return-values&quot;&gt;Emerging JavaScript pattern: multiple return values&lt;/a&gt; (~26.100 views)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/aws-solution-architect-associate-exam-notes-tips&quot;&gt;AWS Solution Architect Associate exam, my notes and tips
&lt;/a&gt; (~16.900 views)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The total number of page views amounted to about 120.000 views, which compared to the previous year total of 65.000 views is a great 85% increase.&lt;/p&gt;
&lt;p&gt;I should dig in to find out the reason for the increase. I don’t feel like I did anything special (or planned) to drive such improvement.&lt;/p&gt;
&lt;p&gt;For this year, I am not sure I am ready to make any commitment. I want to try and find one or two topics that I am really passionate about and that I can be able to write interesting posts about. Let’s see how it goes.&lt;/p&gt;
&lt;h2 id=&quot;external-posts&quot;&gt;External posts&lt;/h2&gt;
&lt;p&gt;In 2019, I have been writing 3 posts for a new website that is yet to be published. I will disclose the links in the &lt;a href=&quot;https://loige.co/about&quot;&gt;about section&lt;/a&gt; when they are available!&lt;/p&gt;
&lt;h2 id=&quot;open-sourcing&quot;&gt;Open Sourcing&lt;/h2&gt;
&lt;p&gt;In 2019, I did not stop doing my small part to contribute to open source. Here’s a quick list of my main GitHub contributions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/callstack/linaria&quot;&gt;callstack/linaria&lt;/a&gt;: Zero-runtime CSS in JS library (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/fastify-preact-htm-boilerplate&quot;&gt;lmammino/fastify-preact-htm-boilerplate&lt;/a&gt;: Quickly bootstrap your next web app with Fastify, Preact and htm.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/s3-list-bucket-stream&quot;&gt;lmammino/s3-list-bucket-stream&lt;/a&gt;: Node.js stream library that allows you to stream a list of objects from an S3 bucket.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/s3-object-content-stream&quot;&gt;lmammino/s3-object-content-stream&lt;/a&gt;: A Node.js transform stream that gets S3 object keys and emits their actual content.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lorenzofox3/for-await&quot;&gt;lorenzofox3/for-await&lt;/a&gt;: operators and stream semantic for asyncIterators (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/streams-examples&quot;&gt;lmammino/streams-examples&lt;/a&gt;: A bunch of examples on how to use Node.js streams.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/olivere/elastic&quot;&gt;olivere/elastic&lt;/a&gt;: Elasticsearch client for Go (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/lambda-image-colors&quot;&gt;lmammino/lambda-image-colors&lt;/a&gt;: An example AWS Lambda written in GoLang to tag a picture with its prominent colors.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/s3st&quot;&gt;lmammino/s3st&lt;/a&gt;: A command line utility that allows you to stream data from multiple S3 objects directly into your terminal.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/rustlings&quot;&gt;lmammino/rustlings&lt;/a&gt;: random exercises to learn rust (mostly to entertain myself on long plane flights ✈️).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/streams-workshop&quot;&gt;lmammino/streams-workshop&lt;/a&gt;: A workshop on Node.js Streams.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/svgdotjs/svgdotjs.github.io&quot;&gt;svgdotjs/svgdotjs.github.io&lt;/a&gt;: Documentation and website for SVG.js (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/theKashey/rewiremock&quot;&gt;theKashey/rewiremock&lt;/a&gt;: The right way to mock dependencies in Node.js or webpack environment (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/goldbergyoni/nodebestpractices&quot;&gt;goldbergyoni/nodebestpractices&lt;/a&gt;: The largest Node.js best practices list (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Jason3S/xxhash&quot;&gt;Jason3S/xxhash&lt;/a&gt;: Pure JS Implementation of xxhash (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fastify/fastify-etag&quot;&gt;fastify/fastify-etag&lt;/a&gt;: Automatically generate etags for HTTP responses, for Fastify (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fastify/releasify&quot;&gt;fastify/releasify&lt;/a&gt;: A tool to release in a simpler way your module (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fastify/fastify-oauth2&quot;&gt;fastify/fastify-oauth2&lt;/a&gt;: Enable to perform login using oauth2 protocol (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/public-transport-ireland&quot;&gt;lmammino/public-transport-ireland&lt;/a&gt;: Node.js module with utility functions to get real time data for Irish public transport (Irish Rail, Luas, Dublin Bus).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/md-article-template&quot;&gt;lmammino/md-article-template&lt;/a&gt;: A ready-made setup to write articles in Markdown and be able to see live preview and export the article in HTML.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/realtime-transport-dashboards&quot;&gt;lmammino/realtime-transport-dashboards&lt;/a&gt;: Serverless APIs for AWS to build and display public transports real time data (Serverless application example).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fourTheorem/slic-starter&quot;&gt;fourTheorem/slic-starter&lt;/a&gt;: A complete, serverless starter project (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/netcore-node-azure-func-container&quot;&gt;lmammino/netcore-node-azure-func-container&lt;/a&gt;: a repository for Debian 9 containers including net core sdk, node.js and azure functions CLI.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nodejs/node&quot;&gt;nodejs/node&lt;/a&gt;: yes, that’s the Node.js repository! I did a small contribution, but still cool to have one there.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;👍 Comparing last year (22) to this year (24) I had a +9% repo contributions increase. Quite stable I’d say!&lt;/p&gt;
&lt;h2 id=&quot;previous-years-goals&quot;&gt;Previous years goals&lt;/h2&gt;
&lt;p&gt;Now it’s time to check against my &lt;a href=&quot;https://loige.co/2018-a-year-in-review#expectations-for-next-year&quot;&gt;previous year goals&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Keep doing conference talks/workshops (at least 8)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;😭 &lt;strong&gt;Write at least 8 quality blog posts (excluding this one!)&lt;/strong&gt;: did only 3…&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;Keep learning about Security, Machine Learning and networking&lt;/strong&gt;: I guess I did learn something more, but nothing worth a mention…&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;Release Middy v1.0&lt;/strong&gt;: only the beta for now!&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;Publish a new book (or a new edition ✌️)&lt;/strong&gt;: …&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;Get proficient in GoLang&lt;/strong&gt;: I didn’t have many chances at work to keep developing this skill and I ended up investing a bit of my free time on Rust instead…&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;Learn a bit about Social Media and digital marketing&lt;/strong&gt;: read only few blog posts…&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;Keep learning AWS and serverless&lt;/strong&gt;: didn’t do much serverless, or at least not as much as I expected; I barely kept up with the various Serverless news.&lt;/li&gt;
&lt;li&gt;😭 &lt;strong&gt;Get an advanced AWS certification&lt;/strong&gt;. Nope…&lt;/li&gt;
&lt;li&gt;😭 &lt;strong&gt;Play with new database technologies (e.g. CockroachDB &amp;#x26; Clickhouse)&lt;/strong&gt;: this was drive by expected work needs that did not go as expected. Totally dropped it.&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;Improve FullStack bulletin&lt;/strong&gt;: I did some improvements under the hood, but nothing visible outside (as I wanted).&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;More serious and constant BJJ training!&lt;/strong&gt;: not too bad, but could have been better!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Yep I did underdeliver or fail most o my goals, maybe I should set more realistic and coherent goals for this new year!&lt;/p&gt;
&lt;h2 id=&quot;expectations-for-next-year&quot;&gt;Expectations for next year&lt;/h2&gt;
&lt;p&gt;Ok, let’s try to do that then:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Get a new job 😛&lt;/li&gt;
&lt;li&gt;Do only few (invitation based) conferences (3 or 4)&lt;/li&gt;
&lt;li&gt;Write some good quality blog posts (at least 4)&lt;/li&gt;
&lt;li&gt;Release Middy v1.0 stable and have a plan for the future of the framework together with the community around it.&lt;/li&gt;
&lt;li&gt;Publish a new book (or a new edition ✌️)&lt;/li&gt;
&lt;li&gt;Learn more about Rust&lt;/li&gt;
&lt;li&gt;Learn more about Kubernetes&lt;/li&gt;
&lt;li&gt;Keep learning AWS and serverless&lt;/li&gt;
&lt;li&gt;Get an advanced AWS certification&lt;/li&gt;
&lt;li&gt;Improve FullStack bulletin&lt;/li&gt;
&lt;li&gt;More serious and constant BJJ training!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s it for this year review!&lt;/p&gt;
&lt;p&gt;I am not sure what to think if you are still reading… Either you are a stalker or a bot! Or maybe a recruiter, or, hopefully a fellow developer who is trying to make similar career plans.&lt;/p&gt;
&lt;p&gt;If you classify yourself in the latter category, I would really love to know what was your biggest achievement in 2019 and what do you plan to achieve in 2020. If you want to mention some failure as well, that would be super interesting to hear too, especially if you can turn it into a littre retrospective 🙃&lt;/p&gt;
&lt;p&gt;All the best, CIAO!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/2019-a-year-in-review.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/2019-a-year-in-review.png" width="1200" height="630"/></media:content><category>life</category><author>Luciano Mammino</author><comments>https://loige.co/2019-a-year-in-review/#comments</comments><enclosure url="https://loige.co/og/2019-a-year-in-review.png" length="0" type="image/png"/></item><item><title>2020 - A year in review</title><link>https://loige.co/2020-a-year-in-review/</link><guid isPermaLink="true">https://loige.co/2020-a-year-in-review/</guid><description>Luciano Mammino reflects on his 2020, including publishing Node.js Design Patterns Third Edition book, giving 13 conference talks, joining Fabfitfun as Principal Engineer, releasing Middy 1.0, launching Linkerflix MVP, and setting goals for improving as a software engineer, cloud architect, and indie maker in 2021.</description><pubDate>Sat, 02 Jan 2021 12:50:00 GMT</pubDate><content:encoded>&lt;p&gt;As we transition into 2021 and we leave this crazy 2020 behind, it is a great time for me to reflect on my what happened in 2020 from a career perspective and make some plans for the year to come.&lt;/p&gt;
&lt;p&gt;Usual &lt;strong&gt;spoiler alert&lt;/strong&gt;: this is the fifth year in a row for me writing this kind of post. This is going to be a super boring one that I write for myself to reflect on where my career is going and what I am learning every year.&lt;/p&gt;
&lt;p&gt;I hope I am setting the right expectation here. If you decide to go ahead and read this, get comfortable and grab a coffee because it’s going to get quite &lt;em&gt;BOOORING&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;boring stuff ahead&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;250&quot; height=&quot;187&quot; src=&quot;https://loige.co/_astro/booring.DE28yq4-_Z154mlu.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Yeah, this is a boring GIF. A silly attempt to warn you and (hopefully) to make things slightly less boring! 😜&lt;/p&gt;
&lt;h2 id=&quot;an-important-reflection&quot;&gt;An important reflection&lt;/h2&gt;
&lt;p&gt;Before getting started, I want to make a small but important reflection about this crazy 2020, signed by a worldwide pandemic and a global crisis. And, by the way, I dare to remind you that none of this will be magically over just because we are in a new year now… 😟&lt;/p&gt;
&lt;p&gt;This is something that no one could have predicted and it should rightfully shift our perspective towards society and ourself as individuals.&lt;/p&gt;
&lt;p&gt;Of course, I am not going to tell you how you should reconsider your life, but I want to share how I am reconsidering some small elements in mine.&lt;/p&gt;
&lt;p&gt;In the last few years, I have been quite eager to grow as a professional and I tried to accomplish more and more every year, sometimes at the expense of time spent with the people that are dear to me. In retrospective, I recognize that sometimes I might have been a bit too selfish, and I should try hard to change that…&lt;/p&gt;
&lt;p&gt;I have been quite lucky in 2020 because even in these strange times, I have been one of the privileged ones. I work in an industry that it is still thriving (now more than ever) and I didn’t lose my job, nor did I have to take a pay cut. I somehow managed to stay healthy throughout last year and so did most of the people dear to me.&lt;/p&gt;
&lt;p&gt;I hope that most of the people reading this could say the same, but we all can’t ignore the fact that the majority of people out there are struggling and suffering.&lt;/p&gt;
&lt;p&gt;I don’t think, as an individual, that I can have any significant impact to make things better on a large scale, but I can have an impact on my local community and with the people I care about.&lt;/p&gt;
&lt;p&gt;I am not planning anything big here. I want to try to be more aware and careful with the people around. A phone call or just asking &lt;em&gt;“how are you today?”&lt;/em&gt;, &lt;em&gt;“what are you doing?”&lt;/em&gt;, &lt;em&gt;“I was thinking about you…”&lt;/em&gt; or &lt;em&gt;“can I help you with anything?”&lt;/em&gt; could be small gestures but they might mean a lot for the people you care about, even at distance.&lt;/p&gt;
&lt;p&gt;I have tried to do these things a little bit this year, but I’ll try to it more next year. I want to encourage you to do the same.&lt;/p&gt;
&lt;p&gt;In short, I am wishing for 2021 that we can be more compassionate and support each other more.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Together we can face any challenge as deep as the ocean and as high as the sky.&lt;br&gt;
— Sonia Gandhi&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;nodejs-design-patterns---third-edition&quot;&gt;Node.js Design Patterns - Third edition&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/mariocasciaro&quot;&gt;Mario Casciaro&lt;/a&gt; and I have been working on the third edition of &lt;a href=&quot;https://www.nodejsdesignpatterns.com/&quot;&gt;Node.js Desing Patterns (the book)&lt;/a&gt; since September 2019. This new edition finally came out this year at the end of July 2020.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nodejsdesignpatterns.com/&quot;&gt;&lt;img alt=&quot;Node.js Design Patterns book on a table next to a plant&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;670&quot; src=&quot;https://loige.co/_astro/nodejs-design-patterns-book-on-a-table-next-to-a-plant.ReaySeLj_ZsaLjB.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We have been spending countless hours working in tandem on this new edition, which resulted in a full rewrite of the previous edition and a lot of additional new content. The print edition turned out to be massive counting more than 660 pages!&lt;/p&gt;
&lt;p&gt;A lot has changed in the Node.js landscape since 2016 (when we published the second edition) and in this book, we tried to take full advantage of new interesting capabilities like &lt;code&gt;async/await&lt;/code&gt; and &lt;code&gt;ESM&lt;/code&gt;. We have also grown a lot as engineers in the last 4 years and this helped us to put things on a different perspective and improve the overall quality of the book compared to the previous editions.&lt;/p&gt;
&lt;p&gt;We re-imagined the book as a learning path and we decided to add exercises at the end of every chapter. This allows readers to test their understanding of the main concepts. In this perspective, we also created a &lt;a href=&quot;https://github.com/PacktPublishing/Node.js-Design-Patterns-Third-Edition/wiki/Node.js-Design-Patterns-Third-Edition---Exercise-Solutions&quot;&gt;wiki&lt;/a&gt; and a &lt;a href=&quot;https://github.com/PacktPublishing/Node.js-Design-Patterns-Third-Edition/discussions&quot;&gt;discussion board&lt;/a&gt; for readers to exchange opinions and collaborate towards writing their own solutions.&lt;/p&gt;
&lt;p&gt;I am quite proud of the final result and I consider this book one of the greatest achievements of my career so far. A mandatory “thank you” goes to Mario for involving me in this awesome project!&lt;/p&gt;
&lt;p&gt;But this result is not something that can only be attributed to our hard work as authors. It is important to shine a light on all the people that contributed and helped us to make this new edition a reality.&lt;/p&gt;
&lt;p&gt;First and foremost, &lt;strong&gt;all our readers&lt;/strong&gt; from the previous editions. In the last few years, we have collected tons of feedback and ideas on what could have been improved and how. I want to dedicate this new edition to all of them and I hope this book will bring value to the Node.js community as a whole.&lt;/p&gt;
&lt;p&gt;Our publisher, &lt;strong&gt;Packt&lt;/strong&gt;, has been helping us a lot. Packt made sure that this new edition would result in a higher quality product compared to the 2 previous editions.&lt;/p&gt;
&lt;p&gt;Last but not least, the incredible team of &lt;strong&gt;technical reviewers&lt;/strong&gt; made up by some of the most talented engineers I had the pleasure to engage with in my career. This has been the tip of the spear for us and the element that contributed the most to the final quality of the book. I want to thank the reviewers one by one (in random order): &lt;a href=&quot;https://twitter.com/romMiraballes&quot;&gt;Romina Miraballes&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/gbinside&quot;&gt;Roberto Gambuzzi&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/marquicodes&quot;&gt;Kyriakos Markakis&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/liran_tal&quot;&gt;Liran Tal&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/delvedor&quot;&gt;Tomas Della Vedova&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/peterpoliwoda&quot;&gt;Peter Poliwoda&lt;/a&gt;, and &lt;a href=&quot;https://twitter.com/jmwsoft&quot;&gt;Minwoo Jung&lt;/a&gt;. If you are reading this, make sure to follow all of them on Twitter… Trust me, you won’t regret it. 😇&lt;/p&gt;
&lt;p&gt;Unfortunately, I can’t disclose any data, but this new edition has been doing quite well so far. We got some good recognition (if you need a proof of that, you could check out the reviews on Amazon) and it has been ranking quite high on Amazon in several categories (including &lt;em&gt;JavaScript&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Node.js Design Patterns third edition second position on Amazon for the JavaScript category&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1080&quot; height=&quot;966&quot; src=&quot;https://loige.co/_astro/node-js-design-patterns-third-edition-second-position-on-amazon.CeJYWaLz_ZzXORB.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Thanks a lot to &lt;a href=&quot;https://twitter.com/goranjawdat&quot;&gt;Goran Jawdat&lt;/a&gt; for sending us this amazing screenshot!&lt;/p&gt;
&lt;p&gt;If you are interested in finding out more about Node.js Design Patterns, make sure to check out &lt;a href=&quot;https://www.nodejsdesignpatterns.com/&quot;&gt;the official website&lt;/a&gt;. Also, we recently launched a &lt;a href=&quot;https://www.nodejsdesignpatterns.com/blog/&quot;&gt;blog&lt;/a&gt; section that you might want to check out as well!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;These are not books, lumps of lifeless paper, but minds alive on the shelves.&lt;br&gt;
— Gilbert Highet&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;conference-talks&quot;&gt;Conference Talks&lt;/h2&gt;
&lt;p&gt;After a few years involving travelling a lot to speak at many different conferences around the World and with all the effort I put on the third edition of Node.js Design Patterns, I didn’t feel like I wanted to do any talk this year. So, I did not apply for any conference or meetup.&lt;/p&gt;
&lt;p&gt;With that being said, I still ended up delivering 13 different talks, which put me exactly on par with what I did last year!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Luciano Mammino speaking at GCS Connect Serverless Dublin Meetup&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;700&quot; height=&quot;523&quot; src=&quot;https://loige.co/_astro/luciano-mammino-gcs-connect-serverless.IUhaZHto_Z6u29o.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;I was extremely surprised and flattered to have received a lot of invitations to talk at several events. And, yes… when you get an invitation, it’s very hard to say &lt;em&gt;NO&lt;/em&gt;… Needless to say that, in 2020, most of these conferences were remote.&lt;/p&gt;
&lt;p&gt;What made me particularly happy is that some of these talks are not regular tech talks, but interviews about my career path. I am quite happy that I had the opportunity to tell my story and, through my failures and successes, to have an opportunity to inspire other people to try their best every day.&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href=&quot;https://www.youtube.com/channel/UCMudbsRDgdkDe3hXD2qsTUg&quot;&gt;Francesco Sciuti&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/channel/UCckCYs-msiC4Vs_nyg218Hw&quot;&gt;Simone Torrisi&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/c/JavaChallengers/&quot;&gt;Rafael Del Nero&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/channel/UCBRxDSTfr2aJVODDh4WG_7g&quot;&gt;Francesco Ciulla&lt;/a&gt; for interviewing me and everyone else that invited me to speak at their own meetups and conferences! Seriously, &lt;em&gt;THANK YOU&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;This is the full list of talks for my 2020. You can find more details and links in the &lt;a href=&quot;/speaking&quot;&gt;speaking section of this blog&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;“Middy.js: a powerful middleware framework for your Node.js lambdas”&lt;/em&gt;, Dublin GCS Connect Serverless (Dublin, Ireland)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Writing a tech book: it’s doable! (Interview — in Italian)”&lt;/em&gt;, Acadevmy - Uno di frontend (remote)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Is the pot full of gold really in Ireland? (Interview — in Italian)”&lt;/em&gt;, Acadevmy - Chiacchiere per DEVulgare (remote)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“An overview of JavaScript and Node.js”&lt;/em&gt;, Liferay Universities Series (remote)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Node.js scalability tips”&lt;/em&gt;, Shift conference (remote)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Unbundling the JavaScript module bundler”&lt;/em&gt;, Road to Coderful (remote)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Node.js scalability tips”&lt;/em&gt;, CityJS 2020 (remote)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Tomorrowdevs interview (#storiedidevelopers)”&lt;/em&gt;, Tomorrowdevs (remote)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“An Intro to Eleventy: Static Site Generation Made Fun Again”&lt;/em&gt;, CorkDev (remote)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“The path to become a Principal Engineer - interview with Java Challengers”&lt;/em&gt;, Java Challengers (remote)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“Node.js scalability tips”&lt;/em&gt;, Codemotion online 2020 (remote)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“An Intro to Eleventy: Static Site Generation Made Fun Again”&lt;/em&gt;, MancJS (remote)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;“The process of writing a successful programming book”&lt;/em&gt;, Francesco Ciulla’s Channel (remote)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After having delivered a total of 54 talks and workshops in the last few years, I have to admit I feel like I am running out of things to say… Maybe it’s just my imposter syndrome talking, but I am not sure I want to commit to doing any talk for next year. So, I will probably keep this open-ended. If some good opportunity presents itself, I’ll take it…&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I believe in the power of ideas. I believe in the power of sharing knowledge.&lt;br&gt;
— Ory Okolloh&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;career&quot;&gt;Career&lt;/h2&gt;
&lt;p&gt;In 2020 I joined &lt;a href=&quot;http://fabfitfun.com&quot;&gt;Fabfitfun&lt;/a&gt; as a &lt;strong&gt;Principal Software Engineer&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Fabfitfun is delivering happiness and well being to everyione everywhere&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;800&quot; height=&quot;414&quot; src=&quot;https://loige.co/_astro/fabfitfun-mission.DyD7H3E6_Z1l9Tpk.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Fabfitfun is a very interesting company with a lot of technical challenges, regarding very spiky traffic (serving millions of users on a regular basis) and an evolving architecture where we are transitioning from a legacy monolith to a set of decoupled microservices.&lt;/p&gt;
&lt;p&gt;The main headquarter is in Los Angeles, but I joined a new team based in Dublin, which was formed only at the beginning of 2020.&lt;/p&gt;
&lt;p&gt;Even if I have been at Fabfitfun for less than a year I feel like I had several opportunities to have an impact.&lt;/p&gt;
&lt;p&gt;I am currently spending a lot of time wearing many different hats and trying to help in different areas. From building new services (mostly using Python and the excellent &lt;a href=&quot;https://fastapi.tiangolo.com/&quot;&gt;&lt;code&gt;fastapi&lt;/code&gt;&lt;/a&gt; framework), building new &lt;strong&gt;integrations&lt;/strong&gt; and &lt;strong&gt;automation&lt;/strong&gt; around our corporate Slack, optimizing existing solutions around &lt;strong&gt;scalability&lt;/strong&gt;, &lt;strong&gt;security&lt;/strong&gt; and &lt;strong&gt;authentication&lt;/strong&gt; and helping to decouple the legacy monolith into new services deployed on &lt;strong&gt;Kubernetes&lt;/strong&gt;. In the last few months, I have also been organising an internal monthly meetup to help different teams located worldwide to have a place where they can share their passion for technology.&lt;/p&gt;
&lt;p&gt;I admit it has been a bit of a bumpy ride at times. I suppose that starting a new remote office in a crazy unpredictable year like 2020 has been the main reason for some hiccups, but things are getting better as we integrate more with the rest of the company and I am definitely blessed to be working with a world-class team of professionals and to be able to share my expertise every day.&lt;/p&gt;
&lt;p&gt;On top of this, I have been quite lucky I had the chance to visit the headquarter in Los Angeles, just before the whole pandemic exploded.&lt;/p&gt;
&lt;p&gt;Let me prove that to you with a couple of pictures:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Luciano Mammino at the Hollywood sign&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;800&quot; height=&quot;446&quot; src=&quot;https://loige.co/_astro/loige-luciano-mammino-hollywood.DTf5YxD8_Z1USPkg.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;This is me at the Hollywood sign!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Padraig O&amp;amp;#x27;Brien, Luciano Mammino and Roberto Gambuzzi at the Griffith Observatory&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;652&quot; src=&quot;https://loige.co/_astro/loige-gbinside-padraigobrien.YeZc2YrX_1f3dqf.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;From the left to the right: this is &lt;a href=&quot;https://twitter.com/PadraigOBrien&quot;&gt;Padraig O’Brien&lt;/a&gt;, me and &lt;a href=&quot;https://twitter.com/gbinside&quot;&gt;Roberto Gambuzzi&lt;/a&gt; at the Griffith Observatory (yes the one from La La Land).&lt;/p&gt;
&lt;p&gt;And yes… in case you are wondering, we also did a lot of useful work while we were in LA! 😇&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;All things are difficult before they are easy.&lt;br&gt;
— Thomas Fuller&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;side-projects&quot;&gt;Side projects&lt;/h2&gt;
&lt;p&gt;In terms of side projects, 2020 has been an interesting year. I already spoke at length about Node.js Design Patterns, so now let’s discuss &lt;strong&gt;Middy&lt;/strong&gt;, &lt;strong&gt;FullStack Bulletin&lt;/strong&gt; and new project: &lt;strong&gt;Linkerflix&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;middy&quot;&gt;Middy&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://middy.js.org/&quot;&gt;Middy&lt;/a&gt; is a Node.js middleware framework for AWS Lambda. I have been working on this project since the early days of Lambda (even though the first public commit was made the 3rd of August 2017).&lt;/p&gt;
&lt;p&gt;In April 2020 we finally &lt;a href=&quot;/middy-1-is-here&quot;&gt;launched Middy 1.0.0&lt;/a&gt;! After a few years of development and contributions from many awesome engineers, this was a pretty big milestone and I am quite proud of it!&lt;/p&gt;
&lt;p&gt;What’s even better is that throughout the year I found out that several interesting big companies are actually using Middy on a daily basis. Unfortunately, I don’t have an official list, but here I have some proof that the LEGO Group does use Middy!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Hannah from the LEGO Group mentioning that they use Middy as a middleware layer for their Lambdas&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1028&quot; height=&quot;242&quot; src=&quot;https://loige.co/_astro/lego-using-middy.nXC3GMfM_ZrHkJ9.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;This is &lt;a href=&quot;https://twitter.com/hannahintech&quot;&gt;Hannah Tucker McLellan (@hannahintech)&lt;/a&gt; on the &lt;a href=&quot;https://virtual.serverlessdays.io/&quot;&gt;ServerlessDays Virtual October 2020&lt;/a&gt; Discord channel. Thanks to &lt;a href=&quot;https://twitter.com/eoins&quot;&gt;@eoins&lt;/a&gt; for sending me this amazing screenshot and, of course, to Hannah for disclosing this info!&lt;/p&gt;
&lt;p&gt;Interesting enough, I think I reached this milestone a bit burned out regarding the whole project. I haven’t been working a lot with Lambda and serverless in the last couple of years (definitely not as much as I used to do before), so I felt like I was dragging my heels to keep the project alive while I wanted to focus my attention somewhere else.&lt;/p&gt;
&lt;p&gt;Because of this, my release post on this blog turned out to be a little bit of a cry for help to keep the project alive.&lt;/p&gt;
&lt;p&gt;Thankfully the community around the project has been very patient and supporting. In particular, &lt;a href=&quot;https://github.com/willfarrell&quot;&gt;Will Farrell&lt;/a&gt; stepped up and offered to become the lead maintainer of the project. Since then, he has been doing an incredible amount of work releasing other 5 minor versions of the framework and &lt;a href=&quot;https://github.com/middyjs/middy/issues/585&quot;&gt;he is already working on a new major release&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;If you have been using Middy, please consider joining the community and giving back to the project! You can also &lt;a href=&quot;https://github.com/sponsors/willfarrell&quot;&gt;sponsor Will&lt;/a&gt; to support the time he is investing in the project!&lt;/p&gt;
&lt;p&gt;Thanks a lot, Will! 🙌&lt;/p&gt;
&lt;p&gt;One final observation about Middy is that the project has kept growing steadily throughout 2020, surpassing the astonishing number of more than 1 million downloads for the &lt;a href=&quot;https://www.npmjs.com/package/@middy/core&quot;&gt;&lt;code&gt;@middy/core&lt;/code&gt; package&lt;/a&gt; only.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://npm-stat.com/charts.html?package=%40middy%2Fcore&amp;#x26;from=2020-01-01&amp;#x26;to=2021-01-01&quot;&gt;&lt;img alt=&quot;Downloads for @middy/core throughouth 2020&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;993&quot; height=&quot;401&quot; src=&quot;https://loige.co/_astro/middy-downloads-2020.BVALyn0H_ZDlg47.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;These are not crazy big numbers in open source, but they are not small either. Especially if we consider that serverless is still new and there is a lot of potential for growth. If nothing else, these numbers make me proud to have started a project that is giving value to development teams.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: If you want to learn more about what happened for Middy in 2020, Will has done &lt;a href=&quot;https://github.com/middyjs/middy/issues/590&quot;&gt;a great recap on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;fullstack-bulletin&quot;&gt;FullStack Bulletin&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://fullstackbulletin.com/&quot;&gt;FullStack bulletin&lt;/a&gt; is a free weekly newsletter about full stack web development. I have been running this project with my dear friend &lt;a href=&quot;https://twitter.com/andreaman87&quot;&gt;Andrea Mangano&lt;/a&gt; for the last 3 years. The project is totally &lt;a href=&quot;https://github.com/FullStackBulletin&quot;&gt;open source&lt;/a&gt; and uses tons of automation to minimise the amount of manual work.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://fullstackbulletin.com/&quot;&gt;&lt;img alt=&quot;FullStack Bulletin website preview&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1200&quot; height=&quot;648&quot; src=&quot;https://loige.co/_astro/fullstack-bulletin-website-preview.C1nS_0sG_2tFtEC.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In 2020 we didn’t change anything big in the format but the audience kept growing steadily:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The growth of FullStack bulletin in terms of subscribers throughout 2020&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;433&quot; src=&quot;https://loige.co/_astro/fullstack-bulletin-growth-2020.BhTFf_0h_Z1CrxrU.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;One interesting thing is that toward the end of the year we surpassed some of the thresholds around free plans for some of the services we use, so we decided to start asking our subscribers for help.&lt;/p&gt;
&lt;p&gt;If you are interested in supporting FullStack Bulletin, you can do so by &lt;a href=&quot;https://patreon.com/lucianomammino&quot;&gt;donating on Patreon&lt;/a&gt; or &lt;a href=&quot;https://fstack.link/sponsor&quot;&gt;sponsoring&lt;/a&gt; one of the next issues.&lt;/p&gt;
&lt;p&gt;There are probably many ways we can improve FullStack Bulletin, so if you have any suggestion, please do let us know!&lt;/p&gt;
&lt;h3 id=&quot;linkerflix&quot;&gt;Linkerflix&lt;/h3&gt;
&lt;p&gt;In 2020 I decided to start a new small side project: &lt;a href=&quot;https://app.linkerflix.com/&quot;&gt;Linkerflix&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Linkerflix logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;341&quot; height=&quot;96&quot; src=&quot;https://loige.co/_astro/linkerflix-logo.CngUXy7Q_Z25E6PT.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Linkerflix is an idea that was born from the frustration I had while trying to create links to allow readers to buy the book from Amazon. I wanted to have a system that, by using only one link, would automatically redirect the user to the closest Amazon shop. For instance, a user clicking from Italy should be redirected to the book page on Amazon.it while someone in Ireland would go to Amazon.co.uk (we will see if this changes with Brexit, but that’s another topic 😅).&lt;/p&gt;
&lt;p&gt;I have been researching a solution for this for a while until I found out that there’s an official solution from Amazon called &lt;a href=&quot;https://affiliate-program.amazon.com/onelink&quot;&gt;OneLink&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Unfortunately, I didn’t have a great experience while trying to setup OneLink for my account and in the end, I did realize that OneLink only works on a pre-determined website that you have to pre-configure with Amazon (e.g. this blog). Since you have to prove that you own every website you link, you cannot use OneLink on social media channels like Twitter or Youtube… such a bummer!&lt;/p&gt;
&lt;p&gt;To overcome these limitations, in August 2020 I created 2 small alternative open source solutions: &lt;a href=&quot;https://github.com/lmammino/not-one-link&quot;&gt;&lt;code&gt;not-one-link&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/lmammino/not-one-link-lambda&quot;&gt;&lt;code&gt;not-one-link-lambda&lt;/code&gt;&lt;/a&gt;. Yes, the name is a pun! Sorry Amazon… 😇&lt;/p&gt;
&lt;p&gt;Later in the year, as I noticed many content creators suffered the same struggle I faced with sharing links to products on Amazon, I thought it might be a cool idea to try to build a small SaaS service to make it easier to adopt the solutions I already created with &lt;code&gt;not-one-link&lt;/code&gt;. So I took one week off of work and I tried to build a super quick MVP. I documented the entire week on Twitter. If you are curious to see which technologies I used, how I structured the work and what kind of challenges I faced, you can read all the tweets on Threader:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://threader.app/thread/1315716999738265600&quot;&gt;Day 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://threader.app/thread/1316088991016509442&quot;&gt;Day 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://threader.app/thread/1316429789906055168&quot;&gt;Day 3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://threader.app/thread/1316806016726642691&quot;&gt;Day 4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://threader.app/thread/1317168317069742081&quot;&gt;Day 5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://threader.app/thread/1317868855767818241&quot;&gt;Day 6 &amp;#x26; 7&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The next big piece of work in line is more product facing. Now that I have an MVP I have to engage with potential users and try to get their feedback. Hopefully, at the end of this process, I will have found some degree of product market fit… or some new ideas for a pivot!&lt;/p&gt;
&lt;p&gt;I want to dedicate some of my free times in 2021 to focus on this. Wish me luck!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Your first projects aren’t the greatest things in the world, and they may have no money value, they may go nowhere, but that is how you learn - you put so much effort into making something right if it is for yourself.&lt;br&gt;
— Steve Wozniak&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;blog&quot;&gt;Blog&lt;/h2&gt;
&lt;p&gt;If I have to be honest, I feel like I have been failing this blog a little in 2020. The main reason why I think that is because I have published only 3 new articles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/middy-1-is-here&quot;&gt;Middy 1.0.0 is here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/whats-in-a-jwt&quot;&gt;What’s in a JWT (Json Web Token)?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/learning-rust-through-open-source-and-live-code-reviews&quot;&gt;Learning Rust through open source and live code reviews&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Well, it’s easy to say I wasn’t a very prolific author… But let’s see some numbers to check the impact on the blog.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Pageviews and other stats for loige.co in 2020&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2000&quot; height=&quot;422&quot; src=&quot;https://loige.co/_astro/loige-co-stats-2020.Bq7tyYna_Z2qOHEN.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;As you can see from this graph, I got a total of &lt;strong&gt;77.886 pageviews&lt;/strong&gt; (72.043 unique). Compared to last year, where I had almost 120.000 views, it is a significant drop (~35% decrease).&lt;/p&gt;
&lt;p&gt;It is also interesting to see that what’s driving most of the traffic is old articles:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Top articles 2020 for loige.co&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1200&quot; height=&quot;526&quot; src=&quot;https://loige.co/_astro/loige-co-top-articles-in-2020.Gwzsgmk6_Z2syjiU.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;And, also that visitors are coming mostly through organic search:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Traffic sources for loige.co in 2020&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;643&quot; src=&quot;https://loige.co/_astro/loige-co-traffic-sources-2020.Bl-MoW7t_wIq9g.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;I am not a consistent author and I have been struggling for years to come up with a backlog of article ideas to pursue. I am not sure I want to make a promise to change this in 2021. Maybe I should just accept that I will keep blogging randomly and that this is not an area where I need to be consistent.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I’ve never managed to keep a journal longer than two weeks.&lt;br&gt;
— J. K. Rowling&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;external-blog-posts&quot;&gt;External blog posts&lt;/h2&gt;
&lt;p&gt;While I haven’t written a lot of new blog posts on this blog, I actually ended up publishing a decent number of articles on other sites. &lt;strong&gt;7 new posts&lt;/strong&gt; to be precise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/loige/create-a-sitemap-for-your-eleventy-website-25h&quot;&gt;Generate a sitemap for your Eleventy website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/loige/add-a-generator-meta-tag-to-your-eleventy-website-48f1&quot;&gt;Add a generator meta tag to your Eleventy website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/loige/what-is-a-jwt-token-302k&quot;&gt;What is a JWT token&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://buddy.works/tutorials/determine-prominent-colors-in-a-picture-your-first-aws-lambda-in-go&quot;&gt;Determine prominent colors in a picture, your first AWS Lambda in Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/loige/getting-started-with-eleventy-in-11-minutes-496j&quot;&gt;Getting started with Eleventy in 11 minutes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://buddy.works/tutorials/integration-testing-for-aws-lambda-in-go-with-docker-compose&quot;&gt;Integration testing for AWS Lambda in Go with Docker-compose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nodejsdesignpatterns.com/blog/5-ways-to-install-node-js/&quot;&gt;5 Ways to install Node.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I am actually lying a little bit here… The two articles about AWS Lambda and Go are something I wrote during 2019 and they just got published this year… So, in reality, I have been publishing only 5 new posts.&lt;/p&gt;
&lt;p&gt;Still, I don’t feel like this is to bad and I don’t want to commit to doing more for next year. At this point, I should embrace the fact that I will write blog posts only when there is something cool that I want to share.&lt;/p&gt;
&lt;p&gt;There is maybe one exception I will try to make about this. I have been reading a bit about SEO during 2020 and I started the &lt;a href=&quot;https://www.nodejsdesignpatterns.com/blog/&quot;&gt;blog section on Node.js Design Patterns website&lt;/a&gt; to experiment with some of the ideas I had while learning more about SEO.&lt;/p&gt;
&lt;p&gt;If I have to be serious about this I will have to publish a few more articles. At least one every month for the next 12 months. I already came up with a list of potential articles, so I am already laying the groundwork here…&lt;/p&gt;
&lt;p&gt;I suppose, at the end of the year, we should be able to review my commitment and see if I managed to stay consistent here! 🤞&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I don’t journal to ‘be productive.’ I don’t do it to find great ideas or to put down prose I can later publish. The pages aren’t intended for anyone but me. It’s the most cost-effective therapy I’ve ever found.&lt;br&gt;
— Tim Ferriss&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;building-a-twitter-audience&quot;&gt;Building a Twitter audience&lt;/h2&gt;
&lt;p&gt;Another area that kept me busy in the second half of 2020 was working on building a Twitter audience. This is nothing new for me. I have been trying to do this for years since I started this blog and joined Twitter.&lt;/p&gt;
&lt;p&gt;What’s changed this year is that I have been trying to take a slightly more conscious and structured approach.&lt;/p&gt;
&lt;p&gt;How am I structuring things?&lt;/p&gt;
&lt;p&gt;Well, before getting into that, let me give some credit to &lt;a href=&quot;https://twitter.com/dvassallo&quot;&gt;Daniel Vassallo&lt;/a&gt; and his great &lt;a href=&quot;https://gumroad.com/l/twitter-audience&quot;&gt;Everyone Can Build a Twitter Audience&lt;/a&gt; course. I watched his course this year and it helped me realise I did not have any plan or strategy.&lt;/p&gt;
&lt;p&gt;In fairness, I don’t think I have come up with a particularly sophisticated plan now, but I have definitely identified some mistakes I was doing and I have tried to correct them. Let me list some of them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I was tweeting a lot of links to articles&lt;/strong&gt; (like a lot!). This is mainly because of the automation I set up for FullStack bulletin. Whenever I found an interesting article related to full stack web development I was tweeting it to add it to the list of selected articles for the next issue of FullStack bulletin. I don’t think tweeting articles is necessarily a bad thing, but it does not help me to express my personal opinion about things or to add colour to interesting tech topics or projects. Since I realised this I moved all these tweets to &lt;a href=&quot;https://twitter.com/fstackbulletin&quot;&gt;FullStack Bulletin’s Twitter account&lt;/a&gt;. Now, whenever there is something article I feel like I want to tweet I ask myself “can I add any valuable comment to this tweet?”. If the answer is yes, then I do share the article with some additional comment, otherwise, I just share it through the FullStack Bulletin profile. I am extending this logic to any retweet. I have stopped almost all retweets unless I feel like I can add some colour to the original tweet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I was not giving enough&lt;/strong&gt;. Building an audience is mostly about &lt;em&gt;giving&lt;/em&gt; and very little about &lt;em&gt;taking&lt;/em&gt;. What I mean by this is that revisiting some of my previous tweets I realised I was not giving my audience many reasons to follow me. Since I realised this mistake I am actually tweeting less, but when I do try to post something meaningful and useful. It can be a quick tip about something I just learned and that might be useful to other engineers. It might be an opinion about a new technology I have been playing with… This also helps to show interest and expertise on a given area and this should encourage people with similar interests to engage more.&lt;/p&gt;
&lt;p&gt;And this brings me to another important mistake: &lt;strong&gt;I was not engaging enough&lt;/strong&gt; with people with similar interests. This is an easy one to fix in principle, but it is one that takes a lot of time. It means you have to spend a lot more time on Twitter &lt;strong&gt;listening&lt;/strong&gt; rather than just &lt;strong&gt;talking&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;To be fair, this one last point was a bit illuminating to me. When I realised this mistake I felt like I have been using Twitter in the wrong way for so long… In fact, I have been using Twitter more as a news broadcasting channel rather than a place for conversations.&lt;/p&gt;
&lt;p&gt;Realising all these mistakes made me change the way I used Twitter and I have a feeling that now I can use it to have better conversations and engage more with people and learn from them.&lt;/p&gt;
&lt;p&gt;But let’s have a look at the numbers to see if all of this had an effect on my followers base:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Loige&amp;amp;#x27;s Twitter followers growth over 2020&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;620&quot; src=&quot;https://loige.co/_astro/loige-twitter-followers-growth-2020.DYTCYTYW_1aCy7b.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;This graph represents the number of new followers month by month. I started changing my behaviours around the end of July 2020 and you can see there is a visible inflexion point there.&lt;/p&gt;
&lt;p&gt;I know that this is not a sophisticated analysis, but I would like to think that I am onto something here. I’ll keep collecting raw data and eventually do a better analysis to try to find some interesting correlation between actions and the number of new followers per month.&lt;/p&gt;
&lt;p&gt;Meanwhile, if you are curious, you can have a look at my &lt;a href=&quot;https://docs.google.com/spreadsheets/d/17s0nxnu3o-JVOE13CouB7m9bpXHVPOGs-MwCE-vWCmc/edit?usp=sharing&quot;&gt;raw data&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you think you’re boring your audience, go slower not faster.&lt;br&gt;
— Gustav Mahler&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;open-source&quot;&gt;Open Source&lt;/h2&gt;
&lt;p&gt;In 2020, I did not stop doing my small part to contribute to open source. Here’s a quick list of my contributions on different projects on GitHub:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/middyjs/middy&quot;&gt;Middy&lt;/a&gt;: Node.js middleware framework for AWS Lambda.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fastify/website&quot;&gt;Fastify website&lt;/a&gt;: Fastify’s website.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/jwtinfo&quot;&gt;jwtinfo&lt;/a&gt;: A command-line tool to get information about JWTs (Json Web Tokens) - my first open source Rust project!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/PacktPublishing/Node.js-Design-Patterns-Third-Edition&quot;&gt;PacktPublishing/Node.js-Design-Patterns-Third-Edition&lt;/a&gt;: Repository with all the code examples from the third edition of Node.js Design Patterns.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/minikube-helm-init-container&quot;&gt;minikube-helm-init-container&lt;/a&gt;: Sample helm based web application using an init container.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/univ&quot;&gt;univ&lt;/a&gt;: Universal JavaScript application example without server side transpilation (React + Fastify).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/unsplash/comment-on-pr&quot;&gt;unsplash/comment-on-pr&lt;/a&gt;: A GitHub Action to comment on the relevant open PR when a commit is pushed (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/luciopaiva/heapify&quot;&gt;luciopaiva/heapify&lt;/a&gt;: The fastest JavaScript priority queue out there. Zero dependencies (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Kevinrob/guzzle-cache-middleware&quot;&gt;Kevinrob/guzzle-cache-middleware&lt;/a&gt;: A HTTP Cache for Guzzle 6. It’s a simple Middleware to be added in the HandlerStack (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/guzzle-fs-cache-middleware&quot;&gt;guzzle-fs-cache-middleware&lt;/a&gt;: A simple FS backed guzzle cache file middleware compatible with php 5.6.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/fastify-preact-htm-boilerplate&quot;&gt;fastify-preact-htm-boilerplate&lt;/a&gt;: Quickly bootstrap your next web app with Fastify, Preact and htm.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/streams-examples&quot;&gt;streams-examples&lt;/a&gt;: A bunch of examples on how to use Node.js streams.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/guzzle-apcu-fs-cache&quot;&gt;guzzle-apcu-fs-cache&lt;/a&gt;: A zero config cache storage for guzzle-cache-middleware that tries to cache on Apcu and fallbacks to filesystem.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/algorust&quot;&gt;algorust&lt;/a&gt;: Randomly playing with algorithms and Rust.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/DataDog/java-dogstatsd-client&quot;&gt;DataDog/java-dogstatsd-client&lt;/a&gt;: a java statsd client library by Datadog (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nodejs/undici&quot;&gt;nodejs/undici&lt;/a&gt;: An HTTP/1.1 client, written from scratch for Node.js (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jsmrcaga/action-netlify-deploy&quot;&gt;jsmrcaga/action-netlify-deploy&lt;/a&gt;: a GitHub Action step to easily deploy on Netlify (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/financial&quot;&gt;financial&lt;/a&gt;: A Zero-dependency TypeScript/JavaScript financial library (based on numpy-financial) for Node.js, Deno and the browser.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/nim-node-hello-world-http-bench&quot;&gt;nim-node-hello-world-http-bench&lt;/a&gt;: A super simple benchmark to compare Nim raw http performance against Node.js.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/denoland/deno_website2&quot;&gt;denoland/deno_website2&lt;/a&gt;: deno.land website (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/react-sca&quot;&gt;react-sca&lt;/a&gt;: A super simple scaffold for React projects for those who believe CreateReactApp is bloated.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/11ty/eleventy-img&quot;&gt;11ty/eleventy-img&lt;/a&gt;: Utility to perform build-time image transformations in Eleventy (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/not-one-link&quot;&gt;not-one-link&lt;/a&gt;: A simple Node.js library that allows you to re-map Amazon links from one country to another (Like Amazon OneLink™️ but simpler to use).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/not-one-link-lambda&quot;&gt;not-one-link-lambda&lt;/a&gt;: An AWS lambda that allows you to host your own alternative of Amazon OneLink™️ to rewrite Amazon URLs.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/kryz81/awesome-nodejs-learning&quot;&gt;kryz81/awesome-nodejs-learning&lt;/a&gt;: About
A list limited to the best Node.js Learning Resources (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mre/idiomatic-rust&quot;&gt;mre/idiomatic-rust&lt;/a&gt;: A peer-reviewed collection of articles/talks/repos which teach concise, idiomatic Rust (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/11ty-sample-project&quot;&gt;11ty-sample-project&lt;/a&gt;: An example project to illustrate the main features of Eleventy.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mattermost/mattermost-webapp&quot;&gt;mattermost/mattermost-webapp&lt;/a&gt;: Webapp of Mattermost server (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/xdesro/personalsit.es&quot;&gt;xdesro/personalsit.es&lt;/a&gt;: A little directory of people’s personal sites (contribution).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/next-sample-file-upload-app&quot;&gt;next-sample-file-upload-app&lt;/a&gt;: Playing with Next.js and building a sample file upload app for educational purposes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a total of 30 projects I have been involved with in 2020. I used to compare this metric year by year, but I am finally realising that it might not make a lot of sense to do so. Some of these contributions are quite small (e.g. a README fix) while others required me a significant investment of multiple hours, days or even weeks.&lt;/p&gt;
&lt;p&gt;I don’t know if there is any decent way to compare my involvement in Open Source between years, but from now on I will be happy as long as I can write something in this section.&lt;/p&gt;
&lt;p&gt;One project that is definitely worth discussing though is &lt;a href=&quot;https://www.fastify.io/&quot;&gt;Fastify website&lt;/a&gt;. This year I didn’t have a lot of time to invest in it and I realised that I have become a blocker for the project. This probably shows that I haven’t structured and documented the project well enough to allow other people to contribute. Of course, this is bad, so definitely an area to improve on for 2021.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Each of us is a unique strand in the intricate web of life and here to make a contribution.&lt;br&gt;
— Deepak Chopra&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;previous-year-goals&quot;&gt;Previous year goals&lt;/h2&gt;
&lt;p&gt;Now it’s finally time to check how I performed against my &lt;a href=&quot;https://loige.co/2019-a-year-in-review#expectations-for-next-year&quot;&gt;previous year goals&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Get a new job&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Do only a few (invitation-based) conferences (3 or 4)&lt;/strong&gt;: I smashed this one (unexpectedly)!&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;Write some good quality blog posts (at least 4)&lt;/strong&gt;: I think I failed at this, unless we want to cumulative count all the blog posts, even outside this blog…&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Release Middy v1.0 stable and have a plan for the future of the framework together with the community around it&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Publish a new book (or a new edition!)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Learn more about Rust&lt;/strong&gt;: I still feel like I am only at the early days, but 2020 was definitely the year were I felt Rust started to click for me!&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Learn more about Kubernetes&lt;/strong&gt;: I definitely did learn a ton about Kubernetes in 10 months at Fabfitfun.&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;Keep learning AWS and serverless&lt;/strong&gt;: I definetely didn’t do much around this area except maybe trying to read some relevant news and articles.&lt;/li&gt;
&lt;li&gt;😭 &lt;strong&gt;Get an advanced AWS certification&lt;/strong&gt;: Definitely failed at this one. I did renew my subscription for A Cloud Guru but then I did not spend enough time to be able to try to get an AWS Solution Architect professional certification…&lt;/li&gt;
&lt;li&gt;😐 &lt;strong&gt;Improve FullStack bulletin&lt;/strong&gt;: FullStack Bulletin definitely kept growing steadily but I feel I didn’t invest any time trying to figure out what could have been improved.&lt;/li&gt;
&lt;li&gt;😭 &lt;strong&gt;More serious and constant BJJ training&lt;/strong&gt;: well… I did stop this one entirely and you can all imagine why in 2020… I compensated it a bit by going for running and a great thank you goes to my dear friend &lt;a href=&quot;https://twitter.com/lucamarchesotti&quot;&gt;Luca (@lucamarchesotti)&lt;/a&gt; for motivating me!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Looking back, I think I have actually achieved more than ever this year. I am not going to lie, this comes a bit unexpected…&lt;/p&gt;
&lt;p&gt;One thing is certain though. I should try to re-asses these goals on a more regular basis, rather than just doing it at the end of the year. I think doing it maybe on a quarterly basis can help me to see if I am on track or not and where it makes sense to spend most of my time.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Exercise to stimulate, not to annihilate. The world wasn’t formed in a day, and neither were we. Set small goals and build upon them.&lt;br&gt;
— Lee Haney&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;expectations-for-2021&quot;&gt;Expectations for 2021&lt;/h2&gt;
&lt;p&gt;Getting close to the end of the year I have been spending a lot of time trying to think where I want my career to go and which areas I might want to invest my time.&lt;/p&gt;
&lt;p&gt;Before giving you my conclusion, let me thank &lt;a href=&quot;https://twitter.com/PadraigOBrien&quot;&gt;Padraig O’Brien&lt;/a&gt; for spending a lot of time mentoring me on this and for triggering some great reflections.&lt;/p&gt;
&lt;p&gt;What I realised is that I want to grow in 3 different directions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Become a better &lt;strong&gt;Software Engineer&lt;/strong&gt;: learn new technologies, step out of my comfort zone of FullStack wen development.&lt;/li&gt;
&lt;li&gt;Become a better &lt;strong&gt;Cloud Architect&lt;/strong&gt;: I think I am currently junior/mid-ish when it comes to cloud architectures. But this is an area where I enjoy a lot spending my time and one where there is an increasing number of opportunities.&lt;/li&gt;
&lt;li&gt;Become a more serious &lt;strong&gt;Indie Maker&lt;/strong&gt; and &lt;strong&gt;startupper&lt;/strong&gt;: I have launched (and failed!) startups before. I have also launched several products. This is not a new one for me, but this year I have been realising that I have always approached this topic mostly from a technology perspective. For this reason, I think I have always delivered well on the tech side, but quite poorly on the product, marketing and overall strategy. I definitely want to have excuses to explore these areas more and become a more complete individual when it comes to build and launch a product.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, based on these 3 broad topics, this year, I want to try to organise some more practical goals in categories:&lt;/p&gt;
&lt;h3 id=&quot;get-better-at-software-engineering&quot;&gt;Get better at Software Engineering&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Continue to get better at Rust&lt;/strong&gt;: I think the language it’s just a tool, but it can definitely help to step outside the comfort zone of higher-level interpreted languages and learn a lot more about lower-level concepts like memory management.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improve Fastify website&lt;/strong&gt;: make sure that it is easy for other people to join the project and contribute.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;become-a-better-cloud-architect&quot;&gt;Become a better Cloud Architect&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Keep learning about AWS and cloud deployments&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Get a new certification&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep learning about Kubernetes&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;become-a-more-serious-indie-maker&quot;&gt;Become a more serious Indie Maker&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Complete the research around Linkerflix&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Launch a new product (either Linkerflix or something else)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep building an audience&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Publish 12 articles on Node.js Design patterns blog&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;In between goals is a thing called life, that has to be lived and enjoyed.&lt;br&gt;
— Sid Caesar&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;Woah! Have you really been reading all this stuff?! At this point, you probably know me better than my mom! 🤣&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A shocked cat&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;185&quot; height=&quot;128&quot; src=&quot;https://loige.co/_astro/shocked-cat.BEcJGKke_Sdf5i.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Well, what can I say? I am flattered, but also curious to know what you think about all that I have been blurting here…&lt;/p&gt;
&lt;p&gt;Definitely do leave a comment and let me know, but also please share what will be your career goals for 2021… I am really curious to find out what you have in mind for yourself!&lt;/p&gt;
&lt;p&gt;Ciao! 👋&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/2020-a-year-in-review.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/2020-a-year-in-review.png" width="1200" height="630"/></media:content><category>life</category><author>Luciano Mammino</author><comments>https://loige.co/2020-a-year-in-review/#comments</comments><enclosure url="https://loige.co/og/2020-a-year-in-review.png" length="0" type="image/png"/></item><item><title>What&apos;s in a JWT (Json Web Token)?</title><link>https://loige.co/whats-in-a-jwt/</link><guid isPermaLink="true">https://loige.co/whats-in-a-jwt/</guid><description>This article explains what JWTs (JSON Web Tokens) are, looking at their internal structure with header, body, and signature. It illustrates how they enable stateless authentication and authorization in distributed systems.</description><pubDate>Mon, 05 Oct 2020 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you ended up on this article, chances are that you have been seeing JWTs (Json Web Tokens) for a while and you are curious to find out what they really are, what’s inside of them and how they actually work! Why did they get so mainstream anyway?! 🤔&lt;/p&gt;
&lt;p&gt;In this article we will be trying to address this topic in a short but (hopefully) effective fashion!&lt;/p&gt;
&lt;h2 id=&quot;its-just-a-string-with-a-well-defined-format&quot;&gt;It’s just a string with a well-defined format&lt;/h2&gt;
&lt;p&gt;JWT stands for &lt;em&gt;JSON Web Token&lt;/em&gt; and such a token is just a string composed by 3 parts:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The three parts of a JSON Web Token&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1350&quot; height=&quot;102&quot; src=&quot;https://loige.co/_astro/jwt-parts.Ca4MeTQ3_Z2q7vGV.webp&quot; &gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;header&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;body&lt;/strong&gt; (sometimes also referred to as &lt;strong&gt;payload&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;a cryptographic &lt;strong&gt;signature&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s have a look at a more concrete example, a JWT looks like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJoZWxsbyI6ImZyb20gSldUIn0.XoByFQCJvii_iOTO4xlz23zXmb4yuzC3gqrWNt3EHrg&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJoZWxsbyI6ImZyb20gSldUIn0.XoByFQCJvii_iOTO4xlz23zXmb4yuzC3gqrWNt3EHrg&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The three parts are separated by a &lt;code&gt;.&lt;/code&gt; (dot) character:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The three parts of a sample JSON Web Token&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1292&quot; height=&quot;262&quot; src=&quot;https://loige.co/_astro/jwt-parts-example.BTFA-sRa_Y9tTr.webp&quot; &gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;header: &lt;code&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;body: &lt;code&gt;eyJoZWxsbyI6ImZyb20gSldUIn0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;signature: &lt;code&gt;XoByFQCJvii_iOTO4xlz23zXmb4yuzC3gqrWNt3EHrg&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Header and Body are JSON strings (yeah, that’s why the are called &lt;em&gt;JSON&lt;/em&gt; web tokens…). This is somewhat hidden, because those two strings are encoded using the &lt;a href=&quot;https://tools.ietf.org/html/rfc4648#section-5&quot;&gt;Base64Url&lt;/a&gt; algorithm (a URL-safe variation of the standard Base64 encoding algorithm).&lt;/p&gt;
&lt;p&gt;If we decode them this is what we get:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;header: &lt;code&gt;{ &quot;alg&quot;: &quot;HS256&quot;, &quot;typ&quot;: &quot;JWT&quot; }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;body: &lt;code&gt;{ &quot;hello&quot;: &quot;from JWT&quot; }&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Which now looks like proper JSON!&lt;/p&gt;
&lt;p&gt;The signature part contains raw bytes which represent a cryptographic signature of header and body. The signature is also encoded using Base64Url and it can be used to verify the authenticity of a token.&lt;/p&gt;
&lt;p&gt;If you try to decode the signature and visualize it a s UTF-8 string you will probably see some rubbish like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;An attempt to try to decode a JWT signature to a UTF-8 string&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;789&quot; height=&quot;113&quot; src=&quot;https://loige.co/_astro/jwt-signature-decoded-to-string.DqVr4VMi_qNiQC.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Again, this is because the signature just contains raw bytes which do not represent a valid UTF-8 string. So yeah, there is no point in trying to decode and visualize a signature. 🤗&lt;/p&gt;
&lt;h2 id=&quot;when-are-jwts-useful&quot;&gt;When are JWTs useful&lt;/h2&gt;
&lt;p&gt;JWTs are mostly used as a mechanism for “stateless” claims exchange. We can define a claim as some piece of information that we want to certify and propagate through various systems.&lt;/p&gt;
&lt;p&gt;A good example is authentication and authorization, were our claims could be information about the user session (user id, roles, etc). Let’s try to discuss this example with a (rather crappy) illustration:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;John authenticating against an Auth server and getting back a JWT&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1349&quot; height=&quot;580&quot; src=&quot;https://loige.co/_astro/jwt-auth-part-1-loige.Dd9BNQ0A_Z1Eic2G.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;John using his JWT to communicate with the pizza service&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1315&quot; height=&quot;641&quot; src=&quot;https://loige.co/_astro/jwt-auth-part-2-loige.Op73B4BC_ZIXQ8K.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;In this picture:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;John is authenticating against an auth server. The auth server recognizes his credentials and gives him back a token&lt;/li&gt;
&lt;li&gt;John can now use the token to connect to specific services, for instance the pizza service.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Every time John makes a request to a service, he will need to attach his token to the request. The service can look at the token to understand if the request can be authorized. The service can read the information embedded within the token to understand that the request is coming from John and can verify that the signature was applied by the Auth server.&lt;/p&gt;
&lt;p&gt;This process is “stateless” because this validation can be done without having to make an explicit request to the Auth server. Of course every service needs to know the Auth server public key to be able to validate the token signature.&lt;/p&gt;
&lt;p&gt;A stateless mechanism like this, is great for distributed systems or, in general, systems that deal with a high load of requests.&lt;/p&gt;
&lt;p&gt;Authentication is not the only use case for JWT. For instance a JWT can also be used to generate confirmation links like “confirm your subscription to this newsletter” or to generate “password reset links”.&lt;/p&gt;
&lt;h2 id=&quot;now-you-can-be-nosy&quot;&gt;Now you can be nosy&lt;/h2&gt;
&lt;p&gt;Now that you know how a JWT token is made you can start to be nosy and look into the JWT tokens you bump into.&lt;/p&gt;
&lt;p&gt;You can copy-paste tokens into &lt;a href=&quot;https://jwt.io&quot;&gt;jwt.io&lt;/a&gt; or use a command-line tool like &lt;a href=&quot;https://github.com/lmammino/jwtinfo&quot;&gt;&lt;code&gt;jwtinfo&lt;/code&gt;&lt;/a&gt; to read the content of the header and the body in plain text.&lt;/p&gt;
&lt;p&gt;Trust me, if you do that you will be surprised by how many interesting information you can find there!&lt;/p&gt;
&lt;h2 id=&quot;closing-notes&quot;&gt;Closing notes&lt;/h2&gt;
&lt;p&gt;JWT tokens are an interesting approach to authentication and they are particularly convenient in distributed systems when we want to minimise the communication and the amount of load to the authentication provider. Once a token is created, it can be validated without the need to call the authentication provider again.&lt;/p&gt;
&lt;p&gt;If you are curious to understand more about how JWT works (and even how you could crack tokens using Node.js 😼) check out this talk I gave a couple of years ago at &lt;a href=&quot;https://buzzjs.com/&quot;&gt;BuzzJS 2018&lt;/a&gt; in the beautiful New York City:&lt;/p&gt;
&lt;div style=&quot;margin-top: 2em; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 2em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://www.youtube.com/embed/uBYdxOQ57nQ&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;While you watch that, you can have &lt;a href=&quot;https://loige.link/jwt-crack-ny&quot;&gt;the slides&lt;/a&gt; too! 🤗&lt;/p&gt;
&lt;p&gt;That’s all for now.&lt;/p&gt;
&lt;p&gt;Thank you and see you on the next post! 👋&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/whats-in-a-jwt.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/whats-in-a-jwt.png" width="1200" height="630"/></media:content><category>jwt</category><author>Luciano Mammino</author><comments>https://loige.co/whats-in-a-jwt/#comments</comments><enclosure url="https://loige.co/og/whats-in-a-jwt.png" length="0" type="image/png"/></item><item><title>Middy 1.0.0 is here</title><link>https://loige.co/middy-1-is-here/</link><guid isPermaLink="true">https://loige.co/middy-1-is-here/</guid><description>The middleware framework Middy reached version 1.0, bringing middleware capabilities to AWS Lambda. This allows cleaner handler code by extracting cross-cutting concerns into reusable middleware.</description><pubDate>Sun, 26 Apr 2020 15:25:00 GMT</pubDate><content:encoded>&lt;p&gt;Middy, the Node.js middleware framework for AWS Lambda, has finally graduated to 1.0.0! A long awaited milestone for the project.&lt;/p&gt;
&lt;p&gt;In this post we will discuss what middy is and what are the main features of this first stable release.&lt;/p&gt;
&lt;h2 id=&quot;what-is-middy&quot;&gt;What is middy&lt;/h2&gt;
&lt;p&gt;If you are hearing about &lt;a href=&quot;https://middy.js.org&quot;&gt;middy&lt;/a&gt; for the first time, middy is a &lt;strong&gt;middleware framework&lt;/strong&gt; for &lt;strong&gt;AWS Lambda&lt;/strong&gt; written in &lt;strong&gt;Node.js&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Middy has the goal to simplify the way you write Lambda code, essentially by providing a convenient middleware abstraction (similar to the ones you find in frameworks such as Express or Fastify). A middleware framework can simplify code re-use, testing and avoid code duplication. Middy also provides a collection of middlewares that can be installed and configured to fullfil very common use cases (authentication, authorization, caching, data validation, deserialization and serialization, etc.).&lt;/p&gt;
&lt;p&gt;Just to give you a feeling of what using middy looks like, here’s a snippet of code:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// import core&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;middy&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@middy/core&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// import some middlewares&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;jsonBodyParser&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@middy/http-json-body-parser&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;httpErrorHandler&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@middy/http-error-handler&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;validator&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@middy/validator&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// This is your common handler, in no way different than what&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// you are used to doing every day in AWS Lambda&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;processPayment&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;context&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// we don&apos;t need to deserialize the body ourself as&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// a middleware will be used to do that&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;creditCardNumber&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;expiryMonth&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;expiryYear&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;cvc&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;nameOnCard&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;amount&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;body&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// do stuff with this data ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// e.g. send it to a payment gateway and record the transaction&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;success&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;payment processed correctly&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Notice that in the handler you only added base business logic (no deserilization,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// validation or error handler), we will add the rest with middlewares&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;inputSchema&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;object&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;object&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;properties&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;creditCardNumber&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;string&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;minLength&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;12&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;maxLength&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;19&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;pattern&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;d+&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;expiryMonth&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;integer&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;minimum&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;maximum&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;12&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;expiryYear&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;integer&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;minimum&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2020&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;maximum&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2027&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;cvc&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;string&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;minLength&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;maxLength&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;pattern&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;d+&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;nameOnCard&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;string&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;amount&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; },&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Insert here all required event properties&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;required&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;creditCardNumber&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Let&apos;s &quot;middyfy&quot; our handler, then we will be able to attach middlewares to it&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;handler&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;middy&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;processPayment&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;jsonBodyParser&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// parses the request body when it&apos;s a JSON and converts it to an object&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;validator&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inputSchema&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; })) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// validates the input&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;httpErrorHandler&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// handles common http errors and returns proper responses&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#AF4238&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#AF4238&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;handler&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// import coreconst middy = require(&amp;#x27;@middy/core&amp;#x27;)// import some middlewaresconst jsonBodyParser = require(&amp;#x27;@middy/http-json-body-parser&amp;#x27;)const httpErrorHandler = require(&amp;#x27;@middy/http-error-handler&amp;#x27;)const validator = require(&amp;#x27;@middy/validator&amp;#x27;)// This is your common handler, in no way different than what// you are used to doing every day in AWS Lambdaconst processPayment = async (event, context) =&gt; {  // we don&amp;#x27;t need to deserialize the body ourself as  // a middleware will be used to do that  const { creditCardNumber, expiryMonth, expiryYear, cvc, nameOnCard, amount } =    event.body  // do stuff with this data ...  // e.g. send it to a payment gateway and record the transaction  return { result: &amp;#x27;success&amp;#x27;, message: &amp;#x27;payment processed correctly&amp;#x27; }}// Notice that in the handler you only added base business logic (no deserilization,// validation or error handler), we will add the rest with middlewaresconst inputSchema = {  type: &amp;#x27;object&amp;#x27;,  properties: {    body: {      type: &amp;#x27;object&amp;#x27;,      properties: {        creditCardNumber: {          type: &amp;#x27;string&amp;#x27;,          minLength: 12,          maxLength: 19,          pattern: &amp;#x27;d+&amp;#x27;,        },        expiryMonth: {          type: &amp;#x27;integer&amp;#x27;,          minimum: 1,          maximum: 12,        },        expiryYear: {          type: &amp;#x27;integer&amp;#x27;,          minimum: 2020,          maximum: 2027,        },        cvc: {          type: &amp;#x27;string&amp;#x27;,          minLength: 3,          maxLength: 4,          pattern: &amp;#x27;d+&amp;#x27;,        },        nameOnCard: { type: &amp;#x27;string&amp;#x27; },        amount: { type: &amp;#x27;number&amp;#x27; },      },      // Insert here all required event properties      required: [&amp;#x27;creditCardNumber&amp;#x27;],    },  },}// Let&amp;#x27;s &amp;#x22;middyfy&amp;#x22; our handler, then we will be able to attach middlewares to itconst handler = middy(processPayment)  .use(jsonBodyParser()) // parses the request body when it&amp;#x27;s a JSON and converts it to an object  .use(validator({ inputSchema })) // validates the input  .use(httpErrorHandler()) // handles common http errors and returns proper responsesmodule.exports = { handler }&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;From the example above, you can see that middy helps you to keep the handler code (the core of your lambda function) as clean as possible. Your handler is now free from having to handle all sorts of pre and post conditions such as data serialization and validation. Managing these pre and post-conditions can be done with the help of default of custom middlewares and those middlewares can easily be reused across different lambdas as needed.&lt;/p&gt;
&lt;p&gt;This is nothing new if you come from frameworks such as Express or Fastify, but surprisingly, this is yet not so common in &lt;em&gt;Lambda-land&lt;/em&gt; and middy is the first (and one of the very few) frameworks that offers you this capability in this context.&lt;/p&gt;
&lt;p&gt;The best feature of middy is that, since it focuses only on the code layer, you can use it with any other infrastructure-level tool you commonly use, including &lt;strong&gt;Terraform&lt;/strong&gt;, &lt;strong&gt;Cloudformation&lt;/strong&gt;, &lt;strong&gt;SAM&lt;/strong&gt; and the &lt;strong&gt;Serverless Framework&lt;/strong&gt;. The integration is seamless, just install and use the library in your code (as you do with any other external dependency from npm).&lt;/p&gt;
&lt;p&gt;Middy is not so new (in open source terms). It has been around for almost 3 years receiving contributions from more 50 different people, it has almost 1500 &lt;a href=&quot;https://github.com/middyjs/middy/stargazers&quot;&gt;GitHub stars&lt;/a&gt; (please give it some more if you are reading this 😇) and &lt;a href=&quot;https://www.npmjs.com/package/@middy/core&quot;&gt;5 digits downloads per week&lt;/a&gt;. Not impressive numbers, but, in my humble opinion, these are numbers good enough to demostrate that there is interest and maturity around the project.&lt;/p&gt;
&lt;p&gt;If you want to find out more about middy from a technical perspective, check out the official website at &lt;a href=&quot;https://middy.js.org/&quot;&gt;middy.org.js&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;whats-in-the-100&quot;&gt;What’s in the 1.0.0&lt;/h2&gt;
&lt;p&gt;The main change in version 1.0.0 is that now the core and the official middlewares are distributed in separated NPM packages. This allows you to install only the packages you actually need, which helps with keeping your lambdas slim and allow them to bootstrap fast.&lt;/p&gt;
&lt;p&gt;Other interesting changes are new official middlewares, bug fixes and a number of improvements in terms of features, stability and usability.&lt;/p&gt;
&lt;p&gt;You can read the full list of changes in the &lt;a href=&quot;https://github.com/middyjs/middy/releases/tag/1.0.0&quot;&gt;release page on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you are already using middy version 0.x, you can read the &lt;a href=&quot;https://github.com/middyjs/middy/blob/1.0.0/UPGRADE.md#upgrade-0x---1x&quot;&gt;dedicated migration guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-community-behind-middy&quot;&gt;The community behind middy&lt;/h2&gt;
&lt;p&gt;I am personally quite impressed and honoured about all the contributions spontaneously provided by the growing community around middy. I want to personally thank you and celebrate all the people that contributed to the project with the following video (click on the picture to see the full &lt;a href=&quot;https://youtu.be/f2zJLi32a6g&quot;&gt;video on Youtube&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://youtu.be/f2zJLi32a6g&quot;&gt;&lt;img alt=&quot;Middy contribution graph evolution&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;600&quot; height=&quot;322&quot; src=&quot;https://loige.co/_astro/git-graph-middy.afuPCU1I_1ejCw.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thank you!&lt;/p&gt;
&lt;h2 id=&quot;whats-next-for-middy&quot;&gt;What’s next for middy&lt;/h2&gt;
&lt;p&gt;This is the hard question for me. The community is definitely asking for a number of interesting things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Better integration with TypeScript (&lt;a href=&quot;https://github.com/middyjs/middy/issues/203&quot;&gt;#203&lt;/a&gt;, &lt;a href=&quot;https://github.com/middyjs/middy/issues/300&quot;&gt;#300&lt;/a&gt;, &lt;a href=&quot;https://github.com/middyjs/middy/issues/316&quot;&gt;#316&lt;/a&gt;, &lt;a href=&quot;https://github.com/middyjs/middy/issues/373&quot;&gt;#373&lt;/a&gt;, &lt;a href=&quot;https://github.com/middyjs/middy/issues/506&quot;&gt;#506&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Better (and more clear) support for promises and Async/Await (&lt;a href=&quot;https://github.com/middyjs/middy/issues/392&quot;&gt;#392&lt;/a&gt;, &lt;a href=&quot;https://github.com/middyjs/middy/issues/414&quot;&gt;#414&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Better documentation (&lt;a href=&quot;https://github.com/middyjs/middy/issues/173&quot;&gt;#173&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All in all, my feeling is that the framework can still be improved a hell of a lot in terms of usability.&lt;/p&gt;
&lt;p&gt;Follow the &lt;a href=&quot;https://github.com/middyjs/middy/issues&quot;&gt;list of issues on GitHub&lt;/a&gt; to find out what are the common topics and feel free to open new issues if you want to suggest new features or improvements.&lt;/p&gt;
&lt;h2 id=&quot;looking-for-help&quot;&gt;Looking for help&lt;/h2&gt;
&lt;p&gt;Here’s the moment where I am to be honest with myself…&lt;/p&gt;
&lt;p&gt;As a maintainer of the project I don’t feel like I did a great job to make this project progress. I limited myself to doing code reviews and merge feature requests quite passively. I have been lacking vision and initiative to be able to steer the project forward and bring it to the next stage.&lt;/p&gt;
&lt;p&gt;The truth is that I haven’t been as involved with serverless as I used to be in the last 2 years. I have probably been lacking perspective and I lost pace with the evolution of serverless and Lambda, so it’s hard for me to be proactive and have a solid vision for the project.&lt;/p&gt;
&lt;p&gt;I want to shed some light on some people that helped carry the project forward and I want to give them a special thank you (in no particular order):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/willfarrell&quot;&gt;@willfarrell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/theburningmonk&quot;&gt;@theburningmonk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/sdomagala&quot;&gt;@sdomagala&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dkatavic&quot;&gt;@dkatavic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vladgolubev&quot;&gt;@vladgolubev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you use middy, don’t be shy and please show yourself on GitHub. I created a new repository just to foster conversations at &lt;a href=&quot;https://github.com/middyjs/discuss&quot;&gt;github.com/middyjs/discuss&lt;/a&gt;. Open an issue just to say hello and tell us how and why you are using middy and what you would like to see happening next.&lt;/p&gt;
&lt;p&gt;I’d love to be able to create a more cohesive community and possibly to pass the torch to a group of people that is actively involved in serverless and that can drive the project forward better than I am currently doing.&lt;/p&gt;
&lt;h2 id=&quot;alternatives-to-middy&quot;&gt;Alternatives to middy&lt;/h2&gt;
&lt;p&gt;In case you don’t like middy or you just want to explore possible alternatives, these are some of the alternatives I know about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/curveball&quot;&gt;curveball&lt;/a&gt; by &lt;a href=&quot;https://github.com/evert&quot;&gt;@evert&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/juliantellez/lambcycle&quot;&gt;lambcycle&lt;/a&gt; by &lt;a href=&quot;https://github.com/juliantellez&quot;&gt;@juliantellez&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dbartholomae/lambda-middleware&quot;&gt;lambda-middleware&lt;/a&gt; by &lt;a href=&quot;https://github.com/dbartholomae&quot;&gt;@dbartholomae&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/awslabs/aws-serverless-express&quot;&gt;aws-serverless-express&lt;/a&gt; by AWS itself&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fastify/aws-lambda-fastify&quot;&gt;aws-lambda-fastify&lt;/a&gt; by the &lt;a href=&quot;https://github.com/fastify&quot;&gt;fastify community&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/blaxk/aws-lambda-middleware&quot;&gt;aws-lambda-middleware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/siroop-ch/nodejs-lambda-middleware&quot;&gt;nodejs-lambda-middleware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lambda-decorators.readthedocs.io/en/latest/&quot;&gt;lambda_decorators&lt;/a&gt; (python)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://honeycombio.github.io/beeline-python/&quot;&gt;beeline&lt;/a&gt; (python)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.rs/vicuna/0.4.1/vicuna/&quot;&gt;vicuna&lt;/a&gt; (rust)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/aws/aws-lambda-go&quot;&gt;aws-lambda-go&lt;/a&gt; (go)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Feel free to suggest me other alternatives in the comments and I’ll happily add them to the article.&lt;/p&gt;
&lt;h2 id=&quot;closing-notes&quot;&gt;Closing notes&lt;/h2&gt;
&lt;p&gt;That’s it. I feel quite happy and relieved to know that we finally reached this milestone and I look forward to seeing what’s next for the project.&lt;/p&gt;
&lt;p&gt;All the best and please let me know in the comments what do you think.&lt;/p&gt;
&lt;p&gt;Regards&lt;/p&gt;
&lt;p&gt;PS: thanks to &lt;a href=&quot;https://twitter.com/theburningmonk&quot;&gt;@theburningmonk&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/StefanoAbalsamo&quot;&gt;@StefanoAbalsamo&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/PadraigOBrien&quot;&gt;@PadraigOBrien&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/quasi_modal&quot;&gt;@quasi_modal&lt;/a&gt; for feedback and reviews.&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/middy-1-is-here.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/middy-1-is-here.png" width="1200" height="630"/></media:content><category>serverless</category><category>node-js</category><category>javascript</category><author>Luciano Mammino</author><comments>https://loige.co/middy-1-is-here/#comments</comments><enclosure url="https://loige.co/og/middy-1-is-here.png" length="0" type="image/png"/></item><item><title>Lean NPM packages</title><link>https://loige.co/lean-npm-packages/</link><guid isPermaLink="true">https://loige.co/lean-npm-packages/</guid><description>Learn how to configure NPM packages to publish only the files needed by users, avoiding bloating node_modules folders.</description><pubDate>Sun, 08 Sep 2019 16:40:58 GMT</pubDate><content:encoded>&lt;p&gt;Every developer on the planet knows how modular Node.js and the JavaScript ecosystem have become.
This is probably due to the great job that package management systems and registries like &lt;a href=&quot;https://bower.io/&quot;&gt;bower&lt;/a&gt; (discontinued) and &lt;a href=&quot;https://npm.com&quot;&gt;npm&lt;/a&gt; carried over in the last few years. I personally believe that this is also a consequence of the “many small modules” philosophy that has been popularised within the JavaScript ecosystem.&lt;/p&gt;
&lt;p&gt;This is great, but all that glitters is not gold… Look, for instance, at this picture for a second:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;node_modules heaviest objects in the universe&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;800&quot; height=&quot;575&quot; src=&quot;https://loige.co/_astro/node_modules_heaviest_objects_in_the_universe.FsN5CPm__1gAbH2.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Yeah you have probably seen this picture before and it’s probably not funny anymore… Anyway, this picture is a good summary right there on how this “many small modules” idea got a little bit out of hand within the JavaScript ecosystem.&lt;/p&gt;
&lt;p&gt;Every time you run &lt;code&gt;npm install&lt;/code&gt; you basically start to get so many files that you might feel like you are downloading the entire world wide  into your hard drive! 😰&lt;/p&gt;
&lt;p&gt;There are even tools that try to scout for &lt;code&gt;node_modules&lt;/code&gt; folders in your system and get rid of them (E.g. &lt;a href=&quot;https://www.npmjs.com/package/wipe-modules&quot;&gt;&lt;code&gt;wipe-modules&lt;/code&gt;&lt;/a&gt;). There are also some developers who showed how all the &lt;code&gt;node_modules&lt;/code&gt; folders in their system is making their backups too slow (&lt;a href=&quot;https://t.co/2KirOXF2v2&quot;&gt;see tweet&lt;/a&gt;)!&lt;/p&gt;
&lt;p&gt;Some like to make fun of this issue or they just complain about it. In this article, I don’t want to do any of those things. I’d rather prefer to be a little bit more constructive and try to share some simple techniques to keep your NPM modules as lean as possible, so that other developers will save bandwidth and time when pulling your modules from NPM!&lt;/p&gt;
&lt;h2 id=&quot;repository-vs-registry&quot;&gt;Repository vs Registry&lt;/h2&gt;
&lt;p&gt;In some languages like Go or PHP, what you have in a module repository is exactly what you get through the package manager when trying to install the module. This is because the code you download through the package manager is actually coming straight from the repository (or from a proxy that keeps a copy of the repository). In this cases, the structure of your repository is fundamentally tied to the file structure of your module: what you get by installing a module is pretty much what you would get by cloning the repository.&lt;/p&gt;
&lt;p&gt;NPM doesn’t work this way. In fact, NPM allows you to selectively push files into the registry, so you might end up with a very different file structure compared to what you have in your git repository.&lt;/p&gt;
&lt;p&gt;While this interesting property of the system have caused some security issues in the past (see the &lt;a href=&quot;https://snyk.io/blog/a-post-mortem-of-the-malicious-event-stream-backdoor/&quot;&gt;event-stream module incident&lt;/a&gt; if you are curious), it also offers us an opportunity to be very selective with what we publish and keep the module lean.&lt;/p&gt;
&lt;p&gt;This is especially important if you “build” your JavaScript code (e.g. using Typescript, Babel or a module bundler), so that the “distribution” (&lt;em&gt;dist&lt;/em&gt;) version of your module is the result of a compilation/transpilation/bundling process. In such cases, you don’t need to publish the entire codebase on NPM as your users will be using only the &lt;em&gt;dist&lt;/em&gt; version of your code. The same goes for tests, documentation, images and other files that won’t be used by the users of your module in their codebase, you should keep them only in your repository and avoid to publish them in the registry.&lt;/p&gt;
&lt;p&gt;Conversely, you probably don’t want to keep &lt;em&gt;dist&lt;/em&gt; code in your repository. This code can easily be regenerated by the build toolchain when necessary and there’s no point in tracking changes on the &lt;em&gt;dist&lt;/em&gt; files when what you are really changing over time is the source code. In git you can use &lt;code&gt;.gitignore&lt;/code&gt; to make sure &lt;em&gt;dist&lt;/em&gt; files are kept out of the repository.&lt;/p&gt;
&lt;p&gt;In short, registries are for production-ready code (&lt;em&gt;dist&lt;/em&gt;) while repositories are for development code (&lt;em&gt;src&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;In the rest of this article we will see some ways to configure an NPM package so that all the unnecessary files will be excluded from the registry.&lt;/p&gt;
&lt;h2 id=&quot;publishing-on-npm&quot;&gt;Publishing on NPM&lt;/h2&gt;
&lt;p&gt;With the NPM command line, &lt;a href=&quot;https://docs.npmjs.com/cli/publish&quot;&gt;&lt;code&gt;npm publish&lt;/code&gt;&lt;/a&gt; is the de facto way of publishing new modules (or new versions of a module) into the NPM registry.&lt;/p&gt;
&lt;p&gt;An NPM module is nothing else than a folder with a valid &lt;code&gt;package.json&lt;/code&gt; file in it. It doesn’t have to be a git repository (in reality the definition of what an NPM module can be is a little bit more complicated, to get the full spiel, check out &lt;a href=&quot;https://docs.npmjs.com/misc/developers#what-is-a-package&quot;&gt;the official NPM documentation&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;By default &lt;code&gt;npm publish&lt;/code&gt; will publish all the files in the package directory (including subfolders recursively).&lt;/p&gt;
&lt;p&gt;So the first thing to do is to be careful and make sure that you don’t have sensible files containing passwords, tokens or other sensible information in your project folder. It’s generally a good idea to keep those away from the module folder, just in case…&lt;/p&gt;
&lt;p&gt;You should also try to avoid to keep unrelated files in the same folder. Yeah, I admit that many times I did some quick n’dirty &lt;code&gt;wget&lt;/code&gt; to get something I needed while I was working on a module and ended up with a lot of unrelated stuff published in my module. Please be smarter than me, don’t do that! 😜&lt;/p&gt;
&lt;h2 id=&quot;default-rules&quot;&gt;Default rules&lt;/h2&gt;
&lt;p&gt;Before starting to deep dive into the different ways you can specify the files to be included/excluded when you publish your package, let’s see first what are the default rules.&lt;/p&gt;
&lt;p&gt;No matter what you do, there are some files that are &lt;strong&gt;always excluded&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.*.swp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;._*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.DS_Store&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.hg&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.npmrc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.lock-wscript&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.svn&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.wafpickle-*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;config.gypi&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CVS&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm-debug.log&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Similarly, there are files that are &lt;strong&gt;always included&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;README.md&lt;/code&gt; (and its variants, like &lt;code&gt;README.markdown&lt;/code&gt; or &lt;code&gt;README.rst&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CHANGELOG.md&lt;/code&gt; (and its variants, like &lt;code&gt;CHANGELOG.markdown&lt;/code&gt; or &lt;code&gt;CHANGELOG.rst&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LICENSE&lt;/code&gt; and &lt;code&gt;LICENCE&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that &lt;code&gt;package-lock.json&lt;/code&gt; is NOT automatically included.&lt;/p&gt;
&lt;h2 id=&quot;gitignore--npmignore&quot;&gt;&lt;code&gt;.gitignore&lt;/code&gt; &amp;#x26; &lt;code&gt;.npmignore&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The first interesting property of &lt;code&gt;npm publish&lt;/code&gt; is that, if your folder is also a git repository and you are using a &lt;code&gt;.gitignore&lt;/code&gt; file, all the patterns listed in it will be used to exclude files.&lt;/p&gt;
&lt;p&gt;So, for instance, if you have &lt;code&gt;*.cache&lt;/code&gt; pattern in your &lt;code&gt;.gitignore&lt;/code&gt;, all the files matching the pattern won’t be published in the registry.&lt;/p&gt;
&lt;p&gt;We discussed already that you might want to have different rules between what you track in your repository and what you publish to the registry, so relying on one configuration to ignore files for both targets might not always be a good idea.&lt;/p&gt;
&lt;p&gt;In those cases you can create a more specific file called &lt;code&gt;.npmignore&lt;/code&gt; (which supports exactly the same syntax as &lt;code&gt;.gitignore&lt;/code&gt;). If this file exists, &lt;code&gt;npm publish&lt;/code&gt; will use that to exclude files, rather than using &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This means that there’s no inheritance, the two files are totally independent. If you want a pattern to exclude files for both your repository and your registry, you will have to put the pattern in both configuration files.&lt;/p&gt;
&lt;p&gt;One interesting lesser known (and rarely used) tip is that you can put &lt;code&gt;.npmignore&lt;/code&gt; files also in subdirectories. The patterns specified in these files will apply only to the subtree of directories where the &lt;code&gt;.npmignore&lt;/code&gt; is found.&lt;/p&gt;
&lt;h2 id=&quot;the-files-field&quot;&gt;The &lt;code&gt;files&lt;/code&gt; field&lt;/h2&gt;
&lt;p&gt;If you don’t like the idea of blacklisting some files (in fairness, you might forget to exclude a file with some sensitive information in it…) you can also follow a &lt;em&gt;whitelisting approach&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In fact, NPM allows you to use a field called &lt;code&gt;files&lt;/code&gt; in your &lt;code&gt;package.json&lt;/code&gt; to specify an array of file patterns to include in the package.&lt;/p&gt;
&lt;p&gt;From the &lt;a href=&quot;https://docs.npmjs.com/files/package.json#files&quot;&gt;official documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The optional &lt;code&gt;files&lt;/code&gt; field is an array of file patterns that describes the entries to be included when your package is installed as a dependency. File patterns follow a similar syntax to &lt;code&gt;.gitignore&lt;/code&gt;, but reversed: including a file, directory, or glob pattern (&lt;code&gt;*&lt;/code&gt;, &lt;code&gt;**/*&lt;/code&gt;, and such) will make it so that file is included in the tarball when it’s packed. Omitting the field will make it default to [&lt;code&gt;&quot;*&quot;&lt;/code&gt;], which means it will include all files.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One important rule is that files included with the &lt;code&gt;files&lt;/code&gt; field cannot be excluded through &lt;code&gt;.npmignore&lt;/code&gt;. In other words, the &lt;code&gt;files&lt;/code&gt; field has higher priority than &lt;code&gt;.npmignore&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;npmignore-vs-the-files-field&quot;&gt;&lt;code&gt;.npmignore&lt;/code&gt; vs the &lt;code&gt;files&lt;/code&gt; field&lt;/h2&gt;
&lt;p&gt;As we said, &lt;code&gt;.npmignore&lt;/code&gt; is effectively a blacklist of files, while the &lt;code&gt;files&lt;/code&gt; field acts as a whitelist.&lt;/p&gt;
&lt;p&gt;This means that, if the &lt;code&gt;files&lt;/code&gt; field is populated, everything is excluded by default and only those files explicitly listed will be included in the packaged tarball.&lt;/p&gt;
&lt;p&gt;You are probably wondering now, should I use the &lt;code&gt;files&lt;/code&gt; field or the &lt;code&gt;.npmignore&lt;/code&gt; file?&lt;/p&gt;
&lt;p&gt;To be honest, I don’t think there’s a silver bullet here. Just pick the mental model (whitelist vs blacklist) that comes easier to you.&lt;/p&gt;
&lt;h2 id=&quot;an-example&quot;&gt;An example&lt;/h2&gt;
&lt;p&gt;I generally prefer to keep my folder structure simple and explicit by having folders for source (&lt;code&gt;src&lt;/code&gt;) and distribution files (&lt;code&gt;dist&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;With this approach you can simply say that &lt;code&gt;src&lt;/code&gt; is what you want to keep in your repo (excluding &lt;code&gt;dist&lt;/code&gt;) and, viceversa, in &lt;code&gt;dist&lt;/code&gt; is what you want to publish on NPM (excluding &lt;code&gt;src&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Just to make a very simple example, let’s say we are building a new library and our code base contains the following files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/index.js&lt;/code&gt;: source code for our module logic (using ES2019 syntax, because we like to be cool! 😎)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/index.test.js&lt;/code&gt;: unit test file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dist/index.js&lt;/code&gt;: distributable version of our module (&lt;em&gt;transpiled&lt;/em&gt; to ES5 with babel)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now we want to keep &lt;code&gt;src/index.js&lt;/code&gt; and &lt;code&gt;src/index.test.js&lt;/code&gt; in our repository (but not in your final package) and &lt;code&gt;dist/index.js&lt;/code&gt; in our package (but not in our repository).&lt;/p&gt;
&lt;p&gt;One way we can achieve this result is by adding &lt;code&gt;dist/&lt;/code&gt; to our &lt;code&gt;.gitignore&lt;/code&gt;, this will make sure we never commit files from the dist folder to the repository.
Then we can either use the &lt;code&gt;.npmignore&lt;/code&gt; file or the &lt;code&gt;files&lt;/code&gt; field to specify what goes in our package.&lt;/p&gt;
&lt;p&gt;I personally prefer to use the &lt;code&gt;files&lt;/code&gt; field, which in this case will be super simple.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;some-test-package&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;1.0.0&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;dist/index.js&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;files&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;dist/&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{  &amp;#x22;name&amp;#x22;: &amp;#x22;some-test-package&amp;#x22;,  &amp;#x22;version&amp;#x22;: &amp;#x22;1.0.0&amp;#x22;,  &amp;#x22;main&amp;#x22;: &amp;#x22;dist/index.js&amp;#x22;,  &amp;#x22;files&amp;#x22;: [    &amp;#x22;dist/&amp;#x22;  ]}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Notice that I am also pointing the entrypoint (&lt;code&gt;main&lt;/code&gt;) to our &lt;code&gt;index.js&lt;/code&gt; file in &lt;code&gt;dist&lt;/code&gt;. This is what will be used when our module is imported.&lt;/p&gt;
&lt;p&gt;With this approach I can add all sorts of other files to my repo (e.g. integration tests, functional tests, images, documentation, etc.) and I won’t have to worry about polluting my final package and making the end user download a lot of stuff that they won’t need!&lt;/p&gt;
&lt;h2 id=&quot;testing-the-package-files&quot;&gt;Testing the package files&lt;/h2&gt;
&lt;p&gt;But how do we know if our setup is correct? We don’t want to publish the package just to see if our setup is correct.&lt;/p&gt;
&lt;p&gt;Thankfully there are at least 2 ways to preview what’s gonna end up in the registry with &lt;code&gt;npm publish&lt;/code&gt; without having to actually publish anything.&lt;/p&gt;
&lt;p&gt;The first way is &lt;code&gt;npm pack&lt;/code&gt;, this command will create a tarball that contains all the files that will be published in the registry.&lt;/p&gt;
&lt;p&gt;The output is actually pretty nice and it will list all the included files.&lt;/p&gt;
&lt;p&gt;If we run &lt;code&gt;npm pack&lt;/code&gt; on the package folder from the example above we should see something like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;npm notice&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;npm notice 📦  some-test-package@1.0.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;npm notice === Tarball Contents ===&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;npm notice 74B  dist/index.js&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;npm notice 266B package.json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;npm notice 13B  LICENSE.md&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;npm notice 39B  README.md&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;npm notice === Tarball Details ===&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;npm notice name:          some-test-package&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;npm notice version:       1.0.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;npm notice filename:      some-test-package-1.0.0.tgz&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;npm notice package size:  428 B&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;npm notice unpacked size: 392 B&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;npm notice shasum:        738776acad3cb41c549a884c6f9e946e7f367657&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;npm notice integrity:     sha512-QQS68QqFtfTGE[...]XmPGJpSYqmpKw==&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;npm notice total files:   4&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;npm notice&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;some-test-package-1.0.0.tgz&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm noticenpm notice 📦  some-test-package@1.0.0npm notice === Tarball Contents ===npm notice 74B  dist/index.jsnpm notice 266B package.jsonnpm notice 13B  LICENSE.mdnpm notice 39B  README.mdnpm notice === Tarball Details ===npm notice name:          some-test-packagenpm notice version:       1.0.0npm notice filename:      some-test-package-1.0.0.tgznpm notice package size:  428 Bnpm notice unpacked size: 392 Bnpm notice shasum:        738776acad3cb41c549a884c6f9e946e7f367657npm notice integrity:     sha512-QQS68QqFtfTGE[...]XmPGJpSYqmpKw==npm notice total files:   4npm noticesome-test-package-1.0.0.tgz&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note that only 4 files have been included:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;dist/index.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LICENSE.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;README.md&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An alternative approach is to run &lt;code&gt;npm publish&lt;/code&gt; in &lt;em&gt;dry run&lt;/em&gt; mode with the flag &lt;code&gt;--dry-run&lt;/code&gt;. With this approach no tarball is created but you will see the output of all the files that would be published with a normal &lt;code&gt;npm publish&lt;/code&gt; run.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In summary, these are the main points I wanted to get across with this article:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What you have in your repository can (and probably should) be different from what you publish in the NPM registry.&lt;/li&gt;
&lt;li&gt;You can exclude files by specifying patterns in &lt;code&gt;.npmignore&lt;/code&gt; (similarly to &lt;code&gt;.gitignore&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Alternatively, you can whitelist files by specifying patterns of files to be included in the &lt;code&gt;files&lt;/code&gt; field in your &lt;code&gt;package.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;There’s a list of files that are always included and, similarly, a list of files that are always excluded (see &lt;a href=&quot;#default-rules&quot;&gt;list above&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Be smart and only publish the bare minimum needed for people to use your library: keep your NPM package lean!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With these advices we are probably not going to solve the &lt;code&gt;node_modules&lt;/code&gt; drama, but at least we can do our part to make it a little bit more bearable.&lt;/p&gt;
&lt;p&gt;Please, let me know what you think about these advices here in the comments. Did you know about these configuration options? Did you use other strategies to keep your NPM packages lean?&lt;/p&gt;
&lt;p&gt;I’ll see you in the next article. Until then, keep your NPM modules lean! 🤗📦&lt;/p&gt;
&lt;p&gt;CIAO 👋&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/lean-npm-packages.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/lean-npm-packages.png" width="1200" height="630"/></media:content><category>javascript</category><category>node-js</category><category>npm</category><author>Luciano Mammino</author><comments>https://loige.co/lean-npm-packages/#comments</comments><enclosure url="https://loige.co/og/lean-npm-packages.png" length="0" type="image/png"/></item><item><title>Where to go to learn Rust in 2021</title><link>https://loige.co/where-to-go-to-learn-rust-in-2021/</link><guid isPermaLink="true">https://loige.co/where-to-go-to-learn-rust-in-2021/</guid><description>This article provides a list of free and paid resources to learn Rust in 2021 including books, blogs, videos, newsletters, podcasts, communities, exercises, workshops, and open source projects.</description><pubDate>Sun, 28 Mar 2021 19:55:00 GMT</pubDate><content:encoded>&lt;p&gt;In this article, we want to provide a list of some free and paid resources that we loved the most in our journey to learning Rust.&lt;/p&gt;
&lt;p&gt;Rust is certainly not the easiest of programming languages, especially at first glance, but once you can overcome the initial “wall of fear” and start to grasp some of the key concepts, Rust becomes a language that you are going to love and you will probably be looking for more and more excuses to use it and learn it further. For this reason, we wanted to collect a list of resources that can help new Rust adventures to find their path towards becoming real “rustaceans”.&lt;/p&gt;
&lt;p&gt;It’s important to mention that this list is totally subjective and not comprehensive. We are only listing material that we had a chance to explore and that we enjoyed. We are sure there is still a lot of great content out there that we haven’t found yet! So if you think something is missing here, let us know in the comments box below! We will also be mentioning some paid content, but we are not receiving any fee or using referral links when we mention these resources.&lt;/p&gt;
&lt;h2 id=&quot;who-are-we&quot;&gt;Who are we&lt;/h2&gt;
&lt;p&gt;Just to put this in context, this article is written by Luciano and Stjepan, 2 software engineers with different backgrounds and expertise who came to love Rust. If you want to know more about us and understand why we are enjoying Rust, check out our bios at the end of this post.&lt;/p&gt;
&lt;h2 id=&quot;free-material&quot;&gt;Free material&lt;/h2&gt;
&lt;h3 id=&quot;official-guides&quot;&gt;Official guides&lt;/h3&gt;
&lt;h4 id=&quot;the-rust-programming-language---aka-the-book&quot;&gt;The Rust Programming Language - a.k.a. “The book”&lt;/h4&gt;
&lt;p&gt;The obvious place to start is the official &lt;a href=&quot;https://doc.rust-lang.org/book/&quot;&gt;Rust book&lt;/a&gt;! The Rust Programming Language is an open-book written by Steve Klabnik and Carol Nichols is a must-read for everyone starting their journey with Rust. It is a quite comprehensive document that explores all the main Rust concepts with very clear examples and a few interesting projects spanning multiple chapters: from a guessing game on the CLI to a multi-threaded web server. The best part of it is that it is a free resource, maintained by the Rust community itself. It has been kept up to date during the last few years, so it’s a resource you can always come back to if you want to review some of the topics you are struggling with.&lt;/p&gt;
&lt;h4 id=&quot;rust-by-example&quot;&gt;Rust by example&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://doc.rust-lang.org/stable/rust-by-example/&quot;&gt;Rust by example&lt;/a&gt; is another wonderful official resource. It is structured as a book, but it feels more like a cheat sheet. It is divided into small chapters and subchapters. Every section is something you can read in about 5 minutes to learn a new Rust concept. You can treat it as reference material and you can get back to it anytime you struggle to remember some specific details like how do you write a unit test or what’s the exact syntax of a &lt;code&gt;match&lt;/code&gt; block. The reason why we love this resource is that it puts a lot of focus on the code. There is certainly more code than text and you will be learning by reading code and comment blocks embedded in the code; a great way to get used to the Rust syntax while you learn the concepts around the language.&lt;/p&gt;
&lt;h4 id=&quot;the-rustonomicon&quot;&gt;The Rustonomicon&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://doc.rust-lang.org/nomicon/&quot;&gt;The Rustonomicon&lt;/a&gt; is a free book for those who are already pretty confident with Rust and want to learn &lt;em&gt;the dark arts of unsafe Rust&lt;/em&gt;! Rust can have portions of code that are &lt;em&gt;unsafe&lt;/em&gt;. What that means is that the compiler will let you do things that might be unsafe and it’s up to you to use this power responsibly. Unsafe code is not necessarily bad but needs to be used with caution and this book will guide you through all the nitty-gritty details that you need to be aware of before starting to write unsafe Rust. Read it if you want to avoid &lt;em&gt;unleashing indescribable horrors&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://doc.rust-lang.org/nomicon/&quot;&gt;&lt;img alt=&quot;The disclaimer at the beginning of the Rustonomicon&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1550&quot; height=&quot;302&quot; src=&quot;https://loige.co/_astro/the-rustonomicon-disclaimer.FHCkROZF_1bVNGw.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;non-official-guides&quot;&gt;Non-official guides&lt;/h3&gt;
&lt;h4 id=&quot;rust-design-patterns&quot;&gt;Rust Design Patterns&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://rust-unofficial.github.io/patterns/&quot;&gt;Rust Design Patterns&lt;/a&gt; is another open-book that is focused on teaching idiomatic Rust. It explores some Rust specific concepts but also revisits the classic &lt;strong&gt;behavioural&lt;/strong&gt;, &lt;strong&gt;creational&lt;/strong&gt; and &lt;strong&gt;structural&lt;/strong&gt; design patterns and adapts them to the Rust idioms. Of course, it also takes the opportunity to explore idiomatic Rust patterns such as &lt;em&gt;RAII&lt;/em&gt; and &lt;em&gt;NewType&lt;/em&gt;. As you might have noticed if you know us, we are real fans of design patterns, so we couldn’t skip this book! Check it out after you have completed The Book and Rust by example.&lt;/p&gt;
&lt;h4 id=&quot;possible-rust&quot;&gt;Possible Rust&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://www.possiblerust.com&quot;&gt;Possible Rust&lt;/a&gt; is a beautifully designed website that talks about “what’s actually possible with Rust”. The website is divided into 2 main sections: guides and patterns. Guides aim at explaining interesting Rust concepts like Foreign Function Interfaces (FFI), Traits, Enums, etc, while the Patterns section tries to explore interesting gotchas like &lt;a href=&quot;https://www.possiblerust.com/pattern/3-things-to-try-when-you-can-t-make-a-trait-object&quot;&gt;“what can you do when you can’t make a trait object”&lt;/a&gt;. There isn’t a lot of material just yet, but we are sure that this resource is worth checking out and that it will grow over time. Keep it in your bookmarks or feed reader!&lt;/p&gt;
&lt;h4 id=&quot;easy-rust&quot;&gt;Easy Rust&lt;/h4&gt;
&lt;p&gt;Did we already say that Rust is not the easiest language to learn? Well, that’s actually the same premise from which &lt;a href=&quot;https://dhghomon.github.io/easy_rust/&quot;&gt;Easy Rust&lt;/a&gt; is starting from. This is another open-book that tries to approach Rust concepts in a simple way, making them much more approachable and digestible, especially to people that are approaching Rust for the first time or engineers coming from higher-level languages. We especially loved some of the analogies in the book, for instance, pointers are compared to entries in a table of contents of a book. In our opinion, it is a great complement to the official Rust Book, but what makes it even more interesting is that recently the contents of this book were made available also in the form of videos &lt;a href=&quot;https://www.youtube.com/playlist?list=PLfllocyHVgsRwLkTAhG0E-2QxCf-ozBkk&quot;&gt;available on YouTube&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PLfllocyHVgsRwLkTAhG0E-2QxCf-ozBkk&quot;&gt;&lt;img alt=&quot;Easy Rust on YouTube&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;800&quot; height=&quot;510&quot; src=&quot;https://loige.co/_astro/easy-rust-on-youtube.ChYfGnu__ZfVlNf.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;learning-rust&quot;&gt;Learning Rust&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://learning-rust.github.io/&quot;&gt;Learning Rust&lt;/a&gt; is another well-rounded open guide on Rust. With its beautiful website divided into a few major sections, it explores the basics of Rusts but also more advanced concepts such as ownership, borrowing, generics and traits. This resource focuses a lot on providing simple explanations and incentivises learning through reading Rust code with its rich set of code samples.&lt;/p&gt;
&lt;h4 id=&quot;rust-cookbook&quot;&gt;Rust Cookbook&lt;/h4&gt;
&lt;p&gt;Also called “Cookin’ with Rust”, &lt;a href=&quot;https://rust-lang-nursery.github.io/rust-cookbook/&quot;&gt;Rust Cookbook&lt;/a&gt; defines itself as being &lt;em&gt;“a collection of simple examples that demonstrate good practices to accomplish common programming tasks, using the crates of the Rust ecosystem”&lt;/em&gt;. As many of the resources already presented so far, Rust Cookbook is built in the form of an open-book (using mdbooks) so it is completely available as an open-source project. The focus of this book is to complement many of the resources we already described above. It does not try to explore the basics of the language but instead, it takes a practical stance against common everyday problems such as concurrency, compression, cryptography and data structures. For every one of these areas it provides a number of interesting examples and suggests some of the most common third-party libraries (crates) that are generally used to tackle these problems.&lt;/p&gt;
&lt;h4 id=&quot;learn-rust-with-entirely-too-many-linked-lists&quot;&gt;Learn Rust With Entirely Too Many Linked Lists&lt;/h4&gt;
&lt;p&gt;Linked lists are… fun! I mean sort of! Definitely, the kind of thing you have been bogged down implementing if you took a computer science degree. In fairness, there is nothing wrong with linked lists even though they are no one’s favourite for sure!&lt;/p&gt;
&lt;p&gt;So why should we care about linked lists in Rust? Well, &lt;a href=&quot;https://rust-unofficial.github.io/too-many-lists/&quot;&gt;Learn Rust With Entirely Too Many Linked Lists&lt;/a&gt; might provide a good answer to this question.&lt;/p&gt;
&lt;p&gt;Linked are built heavily around references so, if you grasp a little bit of Rust already, you might guess that by building a Linked List in Rust you will have to engage in a bloody fight with the borrow checker! This open-book illustrates a number of different approaches to tackle this challenge and, through a series of failed attempts, you will learn many interesting details about Rust and the borrow checker.&lt;/p&gt;
&lt;p&gt;This resource is definitely recommended if you are starting to feel confident about your Rust knowledge and you want to start exploring more advanced topics in a practical way.&lt;/p&gt;
&lt;h3 id=&quot;blogs&quot;&gt;Blogs&lt;/h3&gt;
&lt;h4 id=&quot;amos-fasterthanlime&quot;&gt;Amos (fasterthanlime)&lt;/h4&gt;
&lt;p&gt;If you want to learn more about Rust, why it is a fantastic language, why and when it might not be so good, and how it is becoming even better, the best place to get into that is &lt;a href=&quot;https://fasterthanli.me/&quot;&gt;Amos (fasterthanlime)‘s  blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Amos has a very engaging writing style. He can write very lengthy posts but they are always extremely enjoyable. Maybe because of his extensive in-depth knowledge, maybe because of his entertaining writing style and the support of the &lt;strong&gt;Cool bear&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://fasterthanli.me/&quot;&gt;&lt;img alt=&quot;A random Cool Bear appears&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1616&quot; height=&quot;270&quot; src=&quot;https://loige.co/_astro/cool-bear.DyYM4TZI_Z1Vynvp.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If there one article you shouldn’t miss in this blog that certainly is &lt;a href=&quot;https://fasterthanli.me/articles/a-half-hour-to-learn-rust&quot;&gt;Half an hour to learn Rust&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;yoshua-wuyts&quot;&gt;Yoshua Wuyts&lt;/h4&gt;
&lt;p&gt;Yoshua has been quite an influential developer in the JavaScript community and we had a chance to meet him at several conferences. Always inspiring, Yoshua has been transitioning more and more to Rust in the latest years and he has been documenting his journey in &lt;a href=&quot;https://blog.yoshuawuyts.com/&quot;&gt;his great blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;His blog is a very good place to learn about async Rust, streams, iterators, etc. Yoshua works on several open-source projects and gives a lot of insight into the pros and cons of async in general.&lt;/p&gt;
&lt;p&gt;Given our background as web developers, our favourite article so far is &lt;a href=&quot;https://blog.yoshuawuyts.com/async-http/&quot;&gt;Async HTTP&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;steve-klabnik&quot;&gt;Steve Klabnik&lt;/h4&gt;
&lt;p&gt;Steve Klabnik is one of the most influential people in the Rust community. No surprise that some of the most influential Rust posts come from &lt;a href=&quot;https://steveklabnik.com/&quot;&gt;his blog&lt;/a&gt;. In this blog, there’s a lot of content on software engineering in general, and on how other languages and their problems (and solutions) compare to Rust.&lt;/p&gt;
&lt;p&gt;If you don’t know where to start, we recommend &lt;a href=&quot;https://steveklabnik.com/writing/rust-has-finally-outgrown-me&quot;&gt;Rust has finally outgrown me&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;tyler-neely&quot;&gt;Tyler Neely&lt;/h4&gt;
&lt;p&gt;If you’re into databases, performance optimization, distributed systems, check out &lt;a href=&quot;https://tylerneely.com/&quot;&gt;Tyler Neely’s blog&lt;/a&gt; and look no further. The author writes about low-level problems, tips and tricks, linux, etc. Their project, &lt;a href=&quot;https://sled.rs/&quot;&gt;Sled&lt;/a&gt; is a fantastic tool if you want to experiment with embedded databases and Rust.&lt;/p&gt;
&lt;h4 id=&quot;luca-palmieri&quot;&gt;Luca Palmieri&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://www.lpalmieri.com/&quot;&gt;A learning journal by Luca Palmieri&lt;/a&gt; is another valuable resource to find Rust learning material. Luca is the author of the in-progress book &lt;em&gt;Zero to Production in Rust&lt;/em&gt; (more on this later) and some of the chapters of the book have been published in the form of blog posts. Luca is a very prolific author and there is really a lot of good material, mostly around web development with Rust. One of our favourite articles is &lt;a href=&quot;https://www.lpalmieri.com/posts/2020-07-04-choosing-a-rust-web-framework-2020-edition/&quot;&gt;Choosing a Rust web framework, 2020 edition&lt;/a&gt; which compares the major Rust web frameworks and provides pointers on which one you should choose for your next web project.&lt;/p&gt;
&lt;h3 id=&quot;streams-youtube--twitch-channels&quot;&gt;Streams (youtube &amp;#x26; twitch channels)&lt;/h3&gt;
&lt;p&gt;If you prefer a more visual way to learn or if you simply enjoy video material, here’s a lit of the Youtube channels and Twitch streams dedicated to Rust that we have been enjoying the most.&lt;/p&gt;
&lt;h4 id=&quot;streaming-rust-with-ryan-levick&quot;&gt;Streaming Rust with Ryan Levick&lt;/h4&gt;
&lt;p&gt;One of our favourite Rust YouTube channels is &lt;a href=&quot;https://www.youtube.com/channel/UCpeX4D-ArTrsqvhLapAHprQ&quot;&gt;Streaming Rust with Ryan Levick&lt;/a&gt;. Ryan is a Microsoft engineer who has been spending a lot of time streaming Rust material. His content is quite varied, there are intro videos for beginners but also more advanced videos like &lt;a href=&quot;https://www.youtube.com/watch?v=tM2r9HD4ivQ&amp;#x26;t=2064s&quot;&gt;static VS dynamic dispatch&lt;/a&gt; or &lt;a href=&quot;https://www.youtube.com/watch?v=jNNz4h3iIlw&quot;&gt;FFI&lt;/a&gt;. What we like the most about Ryan is that he is great at explaining concepts, both simple and complicated ones. Every video is a little gem and the examples are always spot on.&lt;/p&gt;
&lt;p&gt;If you prefer to watch the live versions of his videos you can also &lt;a href=&quot;https://www.twitch.tv/ryanlevick&quot;&gt;find Ryan on Twitch&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/channel/UCpeX4D-ArTrsqvhLapAHprQ&quot;&gt;&lt;img alt=&quot;Streaming Rust with Ryan Levick&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;800&quot; height=&quot;485&quot; src=&quot;https://loige.co/_astro/ryan-levick-rust-stream.uiG5yejr_pfklL.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;jon-gjengset&quot;&gt;Jon Gjengset&lt;/h4&gt;
&lt;p&gt;Jon Gjengset is another brilliant author who is streaming about Rust. He is also another content creator that we admire for his capacity of making complex topics easy and understandable. He has 2 main series about Rust right now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PLqbS7AVVErFiWDOAVrPt7aYmnuuOLYvOa&quot;&gt;Crust of Rust&lt;/a&gt;: a very good series for the mid-level Rustucean who wants to get better with more advanced concepts such as &lt;em&gt;iterators&lt;/em&gt;, &lt;em&gt;smart pointers&lt;/em&gt;, &lt;em&gt;lifetime annotations&lt;/em&gt;, etc.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PLqbS7AVVErFj1t4kWrS5vfvmHpJ0bIPio&quot;&gt;The Unsafe Chronicles&lt;/a&gt;: A deep dive into the world of unsafe Rust.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Currently, &lt;em&gt;The Unsafe Chronicles&lt;/em&gt; series has only one video, but the author recently posted on Twitter that we should be expecting a lot more of his time spent on creating new exciting content! How cool is that?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/jonhoo/status/1375621373297500160&quot;&gt;&lt;img alt=&quot;Jon Gjengset tweeting about his commitment to stream more Rust content&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;800&quot; height=&quot;349&quot; src=&quot;https://loige.co/_astro/jon-gjengset-tweet-about-rust-streams.JFzQH9H7_Z1BrXdv.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you prefer to watch Jon live, you can &lt;a href=&quot;https://www.twitch.tv/jonhoo&quot;&gt;find him on Twitch&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;tim-mcnamara&quot;&gt;Tim McNamara&lt;/h4&gt;
&lt;p&gt;Tim is the author of the book &lt;em&gt;Rust in Action&lt;/em&gt; (more on this later), but he is also a prolific video streamer. He has been doing an excellent introduction to Rust video series called &lt;a href=&quot;https://www.youtube.com/playlist?list=PLwtLEJr-BkXZ9PmoAlqaFdoj47o61TWrS&quot;&gt;Learn Rust Programming&lt;/a&gt;. We think that series is a pretty great place to start with Rust. One of the videos we loved the most is about &lt;a href=&quot;https://www.youtube.com/watch?v=K_NO5wJHFys&amp;#x26;list=PLwtLEJr-BkXZ9PmoAlqaFdoj47o61TWrS&amp;#x26;index=9&amp;#x26;t=187s&quot;&gt;error handling in Rust&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also, special love goes to Tim for doing a &lt;a href=&quot;https://loige.co/learning-rust-through-open-source-and-live-code-reviews&quot;&gt;live review&lt;/a&gt; of Luciano’s first crate (&lt;a href=&quot;https://crates.io/crates/jwtinfo&quot;&gt;jwtinfo&lt;/a&gt;), which is a testament to how much Tim cares about educating people about the Rust programming language.&lt;/p&gt;
&lt;p&gt;If you want to follow Tim (you should!) you can find him on &lt;a href=&quot;https://www.youtube.com/c/timClicks&quot;&gt;YouTube&lt;/a&gt; and &lt;a href=&quot;https://www.twitch.tv/timclicks&quot;&gt;Twitch&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;genus-v-programming&quot;&gt;Genus-v programming&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/c/GenusvProgramming&quot;&gt;Genus-v programming&lt;/a&gt; is another great YouTube channel with some interesting Rust material. It is mostly focused on web development with Rust and that’s probably why it fell under our radar.&lt;/p&gt;
&lt;p&gt;One of our favourite playlists (unsurprisingly) is &lt;a href=&quot;https://www.youtube.com/playlist?list=PLECOtlti4Psr4hXVX5GuSvLKp0-RZjz93&quot;&gt;Web Development with Rust&lt;/a&gt; which shows how to use Actix to build a GraphQL API and an authentication server.&lt;/p&gt;
&lt;h4 id=&quot;systems-with-jt&quot;&gt;Systems with JT&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/channel/UCrW38UKhlPoApXiuKNghuig&quot;&gt;Systems with JT&lt;/a&gt; is the YouTube channel of Jonathan Turner. Jonathan has been a very active Rust developer. He is the author of &lt;a href=&quot;https://www.nushell.sh/&quot;&gt;Nushell&lt;/a&gt; and, of course, in his channel, he has a good number of videos dedicated to Rust. Right now, our favourite series is the one where Jonathan explains &lt;a href=&quot;https://www.youtube.com/watch?v=xXVyHsRR168&amp;#x26;list=PLP2yfE2-FXdQw0I6O4YdIX_mzBeF5TDdv&quot;&gt;how to create a line editor in Rust&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;newsletters&quot;&gt;Newsletters&lt;/h3&gt;
&lt;p&gt;The two main Newsletter we follow and recommend are &lt;a href=&quot;https://rust.libhunt.com/newsletter&quot;&gt;Awesome Rust Newsletter&lt;/a&gt; and &lt;a href=&quot;https://this-week-in-rust.org/&quot;&gt;This Week in Rust&lt;/a&gt;. Both are excellent resources to keep yourself up to date with the latest news in the Rust world.&lt;/p&gt;
&lt;p&gt;Another resource that is worth recommending, even though it is not strictly a newsletter, is &lt;a href=&quot;https://readrust.net/&quot;&gt;Read Rust&lt;/a&gt;, which provides a collection of really high-quality articles about Rust. You can subscribe to the RSS feed if you want to receive instant notifications for new content!&lt;/p&gt;
&lt;h3 id=&quot;podcasts&quot;&gt;Podcasts&lt;/h3&gt;
&lt;p&gt;As far as we are aware, there isn’t a hell of a lot of Rust podcasts (yet). The two we have been sporadically listening to are &lt;a href=&quot;https://rustacean-station.org/&quot;&gt;The Rustacean Station Podcast&lt;/a&gt; and &lt;a href=&quot;https://newrustacean.com/&quot;&gt;New Rustacean&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Another one that is quite good, although not strictly about Rust, is &lt;a href=&quot;https://www.bikeshed.fm/&quot;&gt;The Bikeshed&lt;/a&gt; which occasionally contains episodes that explore Rust (see &lt;a href=&quot;https://www.bikeshed.fm/133&quot;&gt;#133&lt;/a&gt; and &lt;a href=&quot;https://www.bikeshed.fm/134&quot;&gt;#134&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id=&quot;communities--meetups&quot;&gt;Communities &amp;#x26; Meetups&lt;/h3&gt;
&lt;p&gt;If you like to interact more with the Rust communities there a few “places” we can certainly recommend!&lt;/p&gt;
&lt;p&gt;The first one is the &lt;a href=&quot;https://discord.gg/jrJFDJuTcu&quot;&gt;official Rust Discord community&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Then, there are a few meetup groups that we have been sporadically attending (all virtual at this time): &lt;a href=&quot;https://www.meetup.com/Rust-London-User-Group/&quot;&gt;Rust London&lt;/a&gt;, &lt;a href=&quot;https://www.meetup.com/Rust-Berlin/&quot;&gt;Rust Berlin&lt;/a&gt; and &lt;a href=&quot;https://www.meetup.com/Rust-Dublin/&quot;&gt;Rust Dublin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.meetup.com/Rust-Dublin/&quot;&gt;&lt;img alt=&quot;Rust Dublin logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;600&quot; height=&quot;338&quot; src=&quot;https://loige.co/_astro/rust-dublin.jVp70QNa_Z1PrVDo.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;exercises-and-workshops&quot;&gt;Exercises and Workshops&lt;/h3&gt;
&lt;p&gt;A most recommended way to learn Rust is… practice, practice, practice! But it is possible that you might not have ideas on what to build right now… and, if you do, the specific idea might not provide the easiest of learning curves!&lt;/p&gt;
&lt;p&gt;There are certainly a few resources that we can recommend if you are willing to write more and more Rust code to get better at Rust!&lt;/p&gt;
&lt;p&gt;The first one that we should absolutely mention is &lt;a href=&quot;https://github.com/rust-lang/rustlings/&quot;&gt;Rustlings&lt;/a&gt;. This is an official resource that allows you to practice Rust concepts by giving you exercises and tests (that you can use to validate your solution). The exercises are related to the topics discussed in the official Rust book, so you can do them as you progress through the book.&lt;/p&gt;
&lt;p&gt;Another interesting resource is a workshop by Luca Palmieri called &lt;a href=&quot;https://github.com/LukeMathWalker/build-your-own-jira-with-rust/&quot;&gt;Build your own Jira with Rust&lt;/a&gt;. In this workshop, you start with a semi-structured project and you have to fill in the blanks. Every file is a small Rust lesson and you’ll get to learn a new concept or two by providing a correct implementation.&lt;/p&gt;
&lt;p&gt;Finally, when you start to feel a bit more comfortable with Rust, we do recommend you try to solve the excellent coding challenges proposed by &lt;a href=&quot;https://adventofcode.com/&quot;&gt;Advent of Code&lt;/a&gt; in Rust. We are actually &lt;a href=&quot;https://github.com/lmammino/rust-advent&quot;&gt;doing that&lt;/a&gt; and so far it has been a lot of fun!&lt;/p&gt;
&lt;h3 id=&quot;open-source-projects&quot;&gt;Open-source projects&lt;/h3&gt;
&lt;p&gt;Another interesting thing you could do to solidify your understanding of Rust and learn to write more idiomatic code is to look at the code of famous open-source libraries.&lt;/p&gt;
&lt;p&gt;You don’t have to read all the code line by line (some projects are massive!) but, just having random glances here and there in the code or simply looking at the code structure and the documentation can be very beneficial and you could learn a lot from it.&lt;/p&gt;
&lt;p&gt;Here’s a list of libraries we do recommend you to take a look at:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tokio-rs/tokio&quot;&gt;Tokio&lt;/a&gt;, &lt;a href=&quot;https://github.com/async-rs/async-std&quot;&gt;Async-std&lt;/a&gt; and &lt;a href=&quot;https://github.com/smol-rs/smol&quot;&gt;Smol&lt;/a&gt; (async runtimes)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/serde-rs/serde&quot;&gt;Serde&lt;/a&gt; (serialization library)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/clap-rs/clap&quot;&gt;Clap&lt;/a&gt; (CLI helper library)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rust-random/rand&quot;&gt;Rand&lt;/a&gt; (random value generation)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/chronotope/chrono&quot;&gt;Chrono&lt;/a&gt; (date and time library)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nannou.cc/&quot;&gt;Nannou&lt;/a&gt; (a creative coding framework)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amethyst.rs/&quot;&gt;Amethyst&lt;/a&gt; and &lt;a href=&quot;https://bevyengine.org/&quot;&gt;Bevy&lt;/a&gt; (game development)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/spacejam/sled&quot;&gt;Sled&lt;/a&gt; (embedded database)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rust-lang/mdBook&quot;&gt;mdbooks&lt;/a&gt; (create a book from markdown)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;paid-material&quot;&gt;Paid material&lt;/h2&gt;
&lt;h3 id=&quot;books&quot;&gt;Books&lt;/h3&gt;
&lt;p&gt;If you like learning by reading books, this list should have you covered.&lt;/p&gt;
&lt;h4 id=&quot;rust-in-action-tim-mcnamara&quot;&gt;Rust in Action (Tim McNamara)&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://www.manning.com/books/rust-in-action&quot;&gt;Rust in Action by Tim McNamara (Manning)&lt;/a&gt; is probably one of our favourite books. It has been in the works for a good number of years but it’s very very close to hitting the press. The book can be already purchased through the Manning MEAP program (you get the digital version and all the updates, then when the print edition is finally available, you’ll receive it by post).&lt;/p&gt;
&lt;p&gt;The reason why we enjoyed this book so much is that it takes a very practical stance. Rust concepts are taught by building interesting projects such as your own floating-point number implementation, a CPU emulator, a custom file format, a key-value store database, etc.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.manning.com/books/rust-in-action&quot;&gt;&lt;img alt=&quot;Tim McNamara - Rust in Action book cover&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;300&quot; height=&quot;398&quot; src=&quot;https://loige.co/_astro/rust-in-action-meap.DCb3AWUU_ZwH59l.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;zero-to-production-in-rust-luca-palmieri&quot;&gt;Zero to Production in Rust (Luca Palmieri)&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.zero2prod.com/&quot;&gt;Zero to Production in Rust by Luca Palmieri (self-published)&lt;/a&gt; is a really good book about backend web development in Rust.
We particularly like this book for various reasons.&lt;/p&gt;
&lt;p&gt;First of all, it’s clearly a work of dedication and love. We had more than one opportunity to speak with Luca and it’s clear how much time and dedication he is putting into this project.&lt;/p&gt;
&lt;p&gt;Since the book is a work in progress, you can read the new chapters as soon as they are available. It’s great to see how the community has been engaging around the project helping the author to make the best out of this book.&lt;/p&gt;
&lt;p&gt;Luca is putting together a book that revolves around one main example: building an e-mail subscription platform. At first glance, one might think this is a very simple example, but in reality, there’s enough complexity around this domain to fill an entire book and, most importantly, learn Rust in the process!&lt;/p&gt;
&lt;p&gt;In addition to this, we love the particular style that the author uses throughout the book. In every chapter, before any piece of code is written, there is an entire section about what the requirements are and why we really need to build a certain feature. Then, every piece of code has its own test and changes are actually introduced with a strict test-driven approach. This is quite unusual for a technical book, but that’s actually why we like this book. While reading it, it seems like you are having a conversation with your product manager or your team lead and you realise you could actually use Rust at work, no big deal!&lt;/p&gt;
&lt;p&gt;We think there is a lot to learn from this book, not just about Rust but even about product development and good software engineering practices. Highly recommended!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Luca Palmieri - Zero to Production in Rust book cover&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;300&quot; height=&quot;416&quot; src=&quot;https://loige.co/_astro/zero-to-production-in-rust-luca-palmieri-book-cover.p57AZ4dT_Z2p6VFq.webp&quot; &gt;&lt;/p&gt;
&lt;h3 id=&quot;programming-rust&quot;&gt;Programming Rust&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/programming-rust-2nd/9781492052586/&quot;&gt;Programming Rust by Jim Blandy, Jason Orendorff and Leonora F.S. Tindall (O’Reilly)&lt;/a&gt; is one of the most popular Rust books out there. We had an opportunity to read the first edition and it’s a very solid book. The second edition should be coming this summer.&lt;/p&gt;
&lt;p&gt;In the first edition, there were a few sections (especially in the first chapters) that were a bit hard to get, but we heard that the authors have been putting a lot of effort in listening to readers feedback and making sure the second edition will come out much more polished and approachable.&lt;/p&gt;
&lt;p&gt;Given the success of the first edition, we are simply looking forward to get our hands on the second edition!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/programming-rust-2nd/9781492052586/&quot;&gt;&lt;img alt=&quot;Programming Rust second edition&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;300&quot; height=&quot;391&quot; src=&quot;https://loige.co/_astro/programming-rust-second-edition-book-cover.BHA50PlQ_2kLCJu.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;the-rust-programming-language-steve-klabnik-carol-nichols&quot;&gt;The Rust Programming Language (Steve Klabnik, Carol Nichols)&lt;/h3&gt;
&lt;p&gt;The Rust Programming Language is the print edition of the actual “official” Rust book that we discussed at the beginning of this post. There isn’t much else to add, except maybe that if you enjoy reading printed books (and want to support the authors), this is a great book to have!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.com/Rust-Programming-Language-Steve-Klabnik-dp-1718500440/dp/1718500440&quot;&gt;&lt;img alt=&quot;The Rust Programming Language book cover&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;300&quot; height=&quot;399&quot; src=&quot;https://loige.co/_astro/rust-programming-language-book-cover.DmwGoxlk_Z2oItmm.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;video-courses&quot;&gt;Video Courses&lt;/h3&gt;
&lt;p&gt;To conclude this article, in this last section, we will explore some paid video courses that you can check if you prefer videos as learning material.&lt;/p&gt;
&lt;h4 id=&quot;rust-in-motion&quot;&gt;Rust in Motion&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://www.manning.com/livevideo/rust-in-motion&quot;&gt;Rust in Motion by Carol Nichols and Jake Goulding (Manning)&lt;/a&gt; is a great video introduction to Rust. The material is geared towards beginners so it’s a great way to start learning Rust.&lt;/p&gt;
&lt;p&gt;One of the things that we have been enjoying the most from this video course is the explanation of Rust lifetimes. We particularly liked how lifetimes are visualised and all the examples presented in the chapter make it easy to understand this fundamental concept of Rust.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.manning.com/livevideo/rust-in-motion&quot;&gt;&lt;img alt=&quot;A screenshot from Rust in motion showing an example of lifetimes visualized&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;600&quot; height=&quot;296&quot; src=&quot;https://loige.co/_astro/rust-in-motion-manning-video-screenshot.BnMDYx40_ZTMX0g.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;building-web-apis-with-rust&quot;&gt;Building web APIs with Rust&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://www.udemy.com/course/web-dev-with-rust-rocket-diesel/&quot;&gt;Building web APIs with Rust by Paris Liakos (Udemy)&lt;/a&gt; is a quite good beginner-level introduction to building web applications with Rust using &lt;strong&gt;Rocket&lt;/strong&gt; for web framework and &lt;strong&gt;Diesel&lt;/strong&gt; as the ORM.&lt;/p&gt;
&lt;p&gt;In about 2 hours and a half, you could have a feeling for what it means to do web development with Rust.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This concludes our list of resources for learning Rust.&lt;/p&gt;
&lt;p&gt;We really hope you found all the material here useful and we look forward to hearing how your journey to becoming a “rustacean” is going!&lt;/p&gt;
&lt;p&gt;Let us know in the comment which material you are enjoying the most and if you come across some other interesting material that we didn’t mention in this post.&lt;/p&gt;
&lt;p&gt;Until then… enjoy writing Rust code!&lt;/p&gt;
&lt;p&gt;CIAO 👋&lt;/p&gt;
&lt;h2 id=&quot;about-the-authors&quot;&gt;About the authors&lt;/h2&gt;
&lt;h3 id=&quot;stjepan-golemac&quot;&gt;Stjepan Golemac&lt;/h3&gt;
&lt;p&gt;Stjepan is a full-stack engineer with interests in machine learning, high-frequency trading, p2p, decentralization, and Rust. Working mostly with JavaScript and TypeScript in the past, he became a huge fan of Rust mostly because it enables humans to produce safe and usually correct code, but also because of its latency and performance guarantees. If you want to see what he’s been up to, or just want to say hi, you can check out &lt;a href=&quot;https://sgolem.com&quot;&gt;his blog&lt;/a&gt; or send him a message on &lt;a href=&quot;https://twitter.com/SGolemac&quot;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;luciano-mammino&quot;&gt;Luciano Mammino&lt;/h3&gt;
&lt;p&gt;Luciano is the owner and main author of this blog. He is a full-stack developer who, in the latest years, has been focusing more and more on scalable cloud architectures. He has been attracted by Rust because it is a great language to learn and appreciate interesting lower-level details of the programming world like memory management and thread-safety. If you want to find out more about Luciano you can check out the &lt;a href=&quot;https://loige.co/about&quot;&gt;about section&lt;/a&gt; of this website or engage with him &lt;a href=&quot;https://twitter.com/loige&quot;&gt;on Twitter&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/where-to-go-to-learn-rust-in-2021.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/where-to-go-to-learn-rust-in-2021.png" width="1200" height="630"/></media:content><category>rust</category><author>Luciano Mammino</author><comments>https://loige.co/where-to-go-to-learn-rust-in-2021/#comments</comments><enclosure url="https://loige.co/og/where-to-go-to-learn-rust-in-2021.png" length="0" type="image/png"/></item><item><title>How to send gzipped requests with boto3</title><link>https://loige.co/how-to-send-gzipped-requests-with-boto3/</link><guid isPermaLink="true">https://loige.co/how-to-send-gzipped-requests-with-boto3/</guid><description>The boto3 Python SDK allows intercepting requests before they are sent to AWS through an event handler system. This article shows how to use it to gzip the payload of PutMetricData requests sent to CloudWatch.</description><pubDate>Tue, 22 Jun 2021 18:20:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently needed to send a big payload to CloudWatch and I managed to increase my chances of staying within the AWS payload size limit by using gzip encoding on the request body with &lt;code&gt;boto3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Unfortunately, with &lt;code&gt;boto3&lt;/code&gt;, gzip encoding is not enabled by default and it can’t be turned on with some simple boolean flag. To make things worse, as of today, there isn’t a great body of documentation or examples available on how to achieve this. Or maybe I am just terrible at &lt;em&gt;googling&lt;/em&gt;…&lt;/p&gt;
&lt;p&gt;I had to go down the rabbit hole to figure out how to support this use case and, in this article, I want to share what I learned with you.&lt;/p&gt;
&lt;h2 id=&quot;send-gzipped-metrics-to-cloudwatch-using-boto3&quot;&gt;Send gzipped metrics to CloudWatch using boto3&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;UPDATE (2024-02-26)&lt;/strong&gt;: AWS has recently announced automatic GZip support for &lt;code&gt;PutMetricData&lt;/code&gt; requests in the CloudWatch API. This means that, for the specific case of the &lt;code&gt;PutMetricData&lt;/code&gt;, the approach described in this article is not necessary anymore. You can find more details in the &lt;a href=&quot;https://aws.amazon.com/blogs/developer/new-default-payload-compression-for-amazon-cloudwatch-putmetricdata-with-the-aws-sdks/&quot;&gt;official announcement&lt;/a&gt;. This article might still be interesting if you want to learn more about the internals of &lt;code&gt;boto3&lt;/code&gt; and how to use its event system.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ok, this is the TLDR; a little gift for the ones in a rush and who are looking for a quick &lt;em&gt;copy-pastable&lt;/em&gt; solution.&lt;/p&gt;
&lt;p&gt;Be aware that the various AWS SDKs are just a convenience layer in front of the AWS HTTP API. Python and &lt;code&gt;boto3&lt;/code&gt; are no exception. Every time you are calling a method on a &lt;code&gt;boto3&lt;/code&gt; client, you are just sending HTTP requests to AWS behind the scenes…&lt;/p&gt;
&lt;p&gt;This is how you can intercept and modify such HTTP requests before they are sent to AWS:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;boto3&lt;/code&gt; has a built-in event system that, among other things, allows you to intercept (and even modify) HTTP requests that are ready to be forwarded to AWS.&lt;/li&gt;
&lt;li&gt;By using this event system, you can implement an event handler that takes the payload of an outgoing request and gzips it. The same handler can also alter the set of outgoing HTTP headers so that it can indicate the request is gzipped by adding the header &lt;code&gt;Content-Encoding: gzip&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here is a code example that uses a CloudWatch client, intercepts calls to the &lt;code&gt;PutMetricData&lt;/code&gt; API, and gzips the request payload:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; boto3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; gzip&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# Create a CloudWatch client&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;cw_client = boto3.client(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;cloudwatch&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# Get a reference to the event system for that client&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;event_system = cw_client.meta.events&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# Event handler that takes an arbitrary request and gzips its body&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;gzip_request_body&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;kwargs&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;gzipped_body = gzip.compress(request.body)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;request.headers.add_header(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Content-Encoding&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;gzip&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;request.data = gzipped_body&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# Register the event handler (only for CloudWatch PutMetricData!)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;event_system.register(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;before-sign.cloudwatch.PutMetricData&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, gzip_request_body)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# Sends a request&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;cw_client.put_metric_data(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;MetricData&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;MetricName&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;KPIs&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Dimensions&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Name&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;PURCHASES_SERVICE&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Value&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;CoolService&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Name&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;APP_VERSION&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Value&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;1.0&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Unit&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;None&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Value&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;217&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;Namespace&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;CoolApp&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import boto3import gzip# Create a CloudWatch clientcw_client = boto3.client(&amp;#x27;cloudwatch&amp;#x27;)# Get a reference to the event system for that clientevent_system = cw_client.meta.events# Event handler that takes an arbitrary request and gzips its bodydef gzip_request_body(request, **kwargs):    gzipped_body = gzip.compress(request.body)    request.headers.add_header(&amp;#x27;Content-Encoding&amp;#x27;, &amp;#x27;gzip&amp;#x27;)    request.data = gzipped_body# Register the event handler (only for CloudWatch PutMetricData!)event_system.register(&amp;#x27;before-sign.cloudwatch.PutMetricData&amp;#x27;, gzip_request_body)# Sends a requestcw_client.put_metric_data(    MetricData = [        {            &amp;#x27;MetricName&amp;#x27;: &amp;#x27;KPIs&amp;#x27;,            &amp;#x27;Dimensions&amp;#x27;: [                {                    &amp;#x27;Name&amp;#x27;: &amp;#x27;PURCHASES_SERVICE&amp;#x27;,                    &amp;#x27;Value&amp;#x27;: &amp;#x27;CoolService&amp;#x27;                },                {                    &amp;#x27;Name&amp;#x27;: &amp;#x27;APP_VERSION&amp;#x27;,                    &amp;#x27;Value&amp;#x27;: &amp;#x27;1.0&amp;#x27;                },            ],            &amp;#x27;Unit&amp;#x27;: &amp;#x27;None&amp;#x27;,            &amp;#x27;Value&amp;#x27;: 217        },    ],    Namespace=&amp;#x27;CoolApp&amp;#x27;)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;You are welcome! 😜&lt;/p&gt;
&lt;p&gt;Now, if you are curious to know more about my use case and how the &lt;code&gt;boto3&lt;/code&gt; events system works you are more than welcome to keep reading the rest of the article.&lt;/p&gt;
&lt;h2 id=&quot;the-use-case-sending-custom-metrics-to-cloudwatch&quot;&gt;The use case: sending custom metrics to CloudWatch&lt;/h2&gt;
&lt;p&gt;Last week, during my work at &lt;a href=&quot;https://www.fourtheorem.com/&quot;&gt;fourTheorem&lt;/a&gt;, we started to get intermittent alarms for a Lambda in our stack that was failing because of requests to CloudWatch being occasionally throttled.&lt;/p&gt;
&lt;p&gt;Once we looked at the error, the problem was actually quite obvious, but let me give you a simplified overview of what we are doing with this Lambda.&lt;/p&gt;
&lt;p&gt;This Lambda is triggered by a Kinesis stream in which we publish custom metric data from all the other components of our application. The Lambda reads these metrics and publishes them to CloudWatch using the &lt;a href=&quot;https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_PutMetricData.html&quot;&gt;&lt;code&gt;PutMetricData&lt;/code&gt; API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Schematic of a Kinesis stream being processed by a Lambda to collect metrics and send them to CloudWatch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;402&quot; src=&quot;https://loige.co/_astro/boto3-custom-metrics-kinesis-lambda-cloudwatch.BrNlHv4R_mAzHI.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Note that this idea is coming from &lt;a href=&quot;https://github.com/lumigo-io/SAR-async-lambda-metrics&quot;&gt;Lumigo’s SAR async Lambda metrics&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;The issue is that in our original implementation we took the naive approach of submitting 1 data point at a time. Therefore, under load, we would be sending a large number of HTTP requests per second to AWS and we might end up being throttled.&lt;/p&gt;
&lt;p&gt;The solution to the problem is actually quite simple: we can reduce the total number of HTTP requests by sending the data in batches containing multiple data points, rather than sending data points one by one.&lt;/p&gt;
&lt;p&gt;This is actually possible by using the same &lt;code&gt;PutMetricData&lt;/code&gt; API from CloudWatch.&lt;/p&gt;
&lt;h2 id=&quot;cloudwatch-putmetricdata-limits&quot;&gt;CloudWatch &lt;code&gt;PutMetricData&lt;/code&gt; limits&lt;/h2&gt;
&lt;p&gt;So apparently the solution is simple: we just need to send multiple data points for every single &lt;code&gt;PutMetricData&lt;/code&gt; call. But how many?&lt;/p&gt;
&lt;p&gt;A call to this API accepts an array of metrics that looks like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;MetricName&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;SomeMetric1&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Dimensions&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Name&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Dimension1Name&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Value&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Dimension1Value&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# Up to other 9 dimensions here ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Unit&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Count&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Values&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;217&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;220&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;221&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# Up to 150 items here ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Timestamp&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1624290910000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# Up to other 19 metric items here ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;[    {        &amp;#x27;MetricName&amp;#x27;: &amp;#x27;SomeMetric1&amp;#x27;,        &amp;#x27;Dimensions&amp;#x27;: [            {                &amp;#x27;Name&amp;#x27;: &amp;#x27;Dimension1Name&amp;#x27;,                &amp;#x27;Value&amp;#x27;: &amp;#x27;Dimension1Value&amp;#x27;            },            # Up to other 9 dimensions here ...        ],        &amp;#x27;Unit&amp;#x27;: &amp;#x27;Count&amp;#x27;,        &amp;#x27;Values&amp;#x27;: [217, 220, 221], # Up to 150 items here ...        &amp;#x27;Timestamp&amp;#x27;: 1624290910000    },    # Up to other 19 metric items here ...]&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;More details can be found in the documentation for the &lt;a href=&quot;https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_MetricDatum.html&quot;&gt;&lt;code&gt;MetricDatum&lt;/code&gt; type&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As you can tell from the comments in the snippet above, the API has some interesting limits to be considered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Up to &lt;strong&gt;20&lt;/strong&gt; different metrics&lt;/li&gt;
&lt;li&gt;Up to &lt;strong&gt;10&lt;/strong&gt; dimensions per metric&lt;/li&gt;
&lt;li&gt;Up to &lt;strong&gt;150 values&lt;/strong&gt; per metric&lt;/li&gt;
&lt;li&gt;Up to &lt;strong&gt;40 KB&lt;/strong&gt; in size for HTTP POST requests&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt; (2022-08-04): AWS has recently incresed all these limits (by a lot), check out the new limits in their &lt;a href=&quot;https://aws.amazon.com/about-aws/whats-new/2022/08/amazon-cloudwatch-metrics-increases-throughput/&quot;&gt;official announcement post&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, the best case scenario to reduce the number of &lt;code&gt;PutMetricData&lt;/code&gt; requests is to have batches of 20 metrics, but we need to make sure that all this data, once encoded, fits in 40 KB.&lt;/p&gt;
&lt;p&gt;Splitting the metrics in chunks of 20 entries per request is not a big deal. But how do we make sure all the other constraints are respected. Especially the payload size one.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;PutMetricData&lt;/code&gt; documentation page adds an interesting bit of information:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can send a payload compressed by gzip.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It would be convenient to use gzip compression to increase our chances to stay within boundaries.&lt;/p&gt;
&lt;p&gt;At this point, I thought &lt;em&gt;“Ok, probably &lt;code&gt;boto3&lt;/code&gt; is automatically doing the compression for us, because why shouldn’t it?”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But if you have used AWS for long enough, you learn not to give too many things for granted, so… Let’s test this assumption, first!&lt;/p&gt;
&lt;h2 id=&quot;testing-boto3-default-behavior&quot;&gt;Testing &lt;code&gt;boto3&lt;/code&gt; default behavior&lt;/h2&gt;
&lt;p&gt;So, how can we see if the by default &lt;code&gt;boto3&lt;/code&gt; is already gzipping our requests?
Requests are going to AWS and I could think of 3 different ways to inspect how the final HTTP request actually looks when sent to AWS:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use a debugger and step through the execution in the deep corners of the &lt;code&gt;boto3&lt;/code&gt; code.&lt;/li&gt;
&lt;li&gt;Use an HTTP proxy like &lt;a href=&quot;https://portswigger.net/burp/communitydownload&quot;&gt;Burp Suite&lt;/a&gt; to intercept all the outgoing traffic and have a chance to inspect what’s being sent to AWS.&lt;/li&gt;
&lt;li&gt;Use the &lt;a href=&quot;https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html#boto3.session.Session.client&quot;&gt;&lt;code&gt;endpoint_url&lt;/code&gt; parameter&lt;/a&gt; to configure the &lt;code&gt;boto3&lt;/code&gt; client to send requests somewhere else.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I opted for option 3, just because I thought it would be the quickest and easiest for me. I quickly wrote a very simple &lt;a href=&quot;https://gist.github.com/lmammino/34373d61ff28ba34c9c26eb1edad5684&quot;&gt;HTTP debugging server in Node.js&lt;/a&gt; and let it listen for requests at &lt;code&gt;locahost:8000&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;At this point I could simply run the following Python code to see how &lt;code&gt;boto3&lt;/code&gt; would send a &lt;code&gt;PutMetricData&lt;/code&gt; request to AWS:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; boto3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; gzip&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;endpoint_url = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;http://localhost:8000/&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;cw_client = boto3.client(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;cloudwatch&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;endpoint_url&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=endpoint_url, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;use_ssl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;False&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;cw_client.put_metric_data(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;MetricData&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;MetricName&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;TEST_BOTO&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Dimensions&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Name&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;APP_VERSION&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Value&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;1.0&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Unit&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;None&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Value&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;17&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;Namespace&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;BotoTest&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import boto3import gzipendpoint_url = &amp;#x22;http://localhost:8000/&amp;#x22;cw_client = boto3.client(&amp;#x27;cloudwatch&amp;#x27;, endpoint_url=endpoint_url, use_ssl=False)cw_client.put_metric_data(    MetricData = [        {            &amp;#x27;MetricName&amp;#x27;: &amp;#x27;TEST_BOTO&amp;#x27;,            &amp;#x27;Dimensions&amp;#x27;: [                {                    &amp;#x27;Name&amp;#x27;: &amp;#x27;APP_VERSION&amp;#x27;,                    &amp;#x27;Value&amp;#x27;: &amp;#x27;1.0&amp;#x27;                },            ],            &amp;#x27;Unit&amp;#x27;: &amp;#x27;None&amp;#x27;,            &amp;#x27;Value&amp;#x27;: 17        },    ],    Namespace=&amp;#x27;BotoTest&amp;#x27;)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note that I am also using &lt;code&gt;use_ssl=False&lt;/code&gt; because my local endpoint supports only plain HTTP.&lt;/p&gt;
&lt;p&gt;Ok at this point I used all my confidence in AWS and run this script… This is what I got in my debug web server:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Boto3 does not use gzip compression by default&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;598&quot; src=&quot;https://loige.co/_astro/boto3-no-gzip-by-default.DkhbjdUa_ZsGCw0.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;As you can see from the picture above, &lt;code&gt;boto3&lt;/code&gt; does not use gzip compression by default.&lt;/p&gt;
&lt;p&gt;Sad me… 😢 Time to roll up the sleeves and figure out how to gzip the request body manually!&lt;/p&gt;
&lt;h2 id=&quot;the-boto3-events-system&quot;&gt;The &lt;code&gt;boto3&lt;/code&gt; events system&lt;/h2&gt;
&lt;p&gt;After some research, I discovered that &lt;code&gt;boto3&lt;/code&gt; has a &lt;a href=&quot;https://boto3.amazonaws.com/v1/documentation/api/latest/guide/events.html&quot;&gt;built-in event system&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This event system allows you to intercept requests being sent to AWS and alter them before they are sent. You can also intercept responses coming from AWS.&lt;/p&gt;
&lt;p&gt;This is not a very well known feature of &lt;code&gt;boto3&lt;/code&gt;, but I can see it being useful in a couple of circumstances:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Log all outgoing requests and incoming responses (for debugging)&lt;/li&gt;
&lt;li&gt;Alter HTTP requests or HTTP responses to and from AWS to implement custom behaviors (gzipping the payload of outgoing requests is a great example).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to look at a quick example of how to use this feature, here is one: we want to add an &lt;code&gt;x-trace-id&lt;/code&gt; header when we invoke a lambda using &lt;code&gt;boto3&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; boto3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;lambda_client = boto3.client(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;lambda&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# our event handler&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;add_xtrace_header&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;kwargs&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;request.headers.add_header(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;x-trace-id&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;trace-trace&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# get the event system for the lambda_client&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;event_system = lambda_client.meta.events&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# attach an event handler to the client for&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;event_system.register(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;before-sign.lambda.Invoke&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, add_xtrace_header)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# invoke a lambda function&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;lambda_client.invoke(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;FunctionName&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;my-function&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import boto3lambda_client = boto3.client(&amp;#x27;lambda&amp;#x27;)# our event handlerdef add_xtrace_header(request, **kwargs):    request.headers.add_header(&amp;#x27;x-trace-id&amp;#x27;, &amp;#x27;trace-trace&amp;#x27;)# get the event system for the lambda_clientevent_system = lambda_client.meta.events# attach an event handler to the client forevent_system.register(&amp;#x27;before-sign.lambda.Invoke&amp;#x27;, add_xtrace_header)# invoke a lambda functionlambda_client.invoke(FunctionName=&amp;#x27;my-function&amp;#x27;)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The example should be pretty straightforward, but let’s zoom on some interesting details.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An event handler is just a function that receives a number of arguments that depend on the type of event.&lt;/li&gt;
&lt;li&gt;Every &lt;code&gt;boto3&lt;/code&gt; client exposes the event system as &lt;code&gt;client.meta.events&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We can register an event handler by using the &lt;code&gt;register&lt;/code&gt; function on the event system of a given client and pass the event name and the handler to it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The event name is interesting because it follows this specification:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;event-type&gt;.&amp;#x3C;service-name&gt;.&amp;#x3C;operation-name&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;event-type&gt;.&lt;service-name&gt;.&lt;operation-name&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;event-type&lt;/code&gt; is used to indicate the type of event. This is generally representing a phase of the lifecycle of a request. Some examples are &lt;code&gt;provide-client-params&lt;/code&gt;, &lt;code&gt;request-created&lt;/code&gt;, &lt;code&gt;before-sign&lt;/code&gt;, &lt;code&gt;before-send&lt;/code&gt;, and &lt;code&gt;response-received&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;service-name&lt;/code&gt; is the name of the service used. For instance: &lt;code&gt;s3&lt;/code&gt; or &lt;code&gt;cloudwatch&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;operation-name&lt;/code&gt; indicates the type of operation the client is trying to perform (the method). For instance: &lt;code&gt;PutMetricData&lt;/code&gt; or &lt;code&gt;Invoke&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not all these parts are mandatory and you can create event listeners for multiple events. Let’s look at some examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;*&lt;/code&gt; will listen to every event&lt;/li&gt;
&lt;li&gt;&lt;code&gt;after-call.lambda.*&lt;/code&gt; (or &lt;code&gt;after-call.lambda&lt;/code&gt;) will listen to all &lt;code&gt;after-call&lt;/code&gt; type events for lambda and intercept all methods.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;botocore&lt;/code&gt; documentation isn’t very clear on how these events work, but after some digging, I managed to find the slides of a very interesting talk by &lt;a href=&quot;https://twitter.com/thekyleknapp&quot;&gt;Kyle Knapp&lt;/a&gt; called &lt;a href=&quot;https://pages.awscloud.com/rs/112-TZM-766/images/B-4.pdf&quot;&gt;Deep Dive on AWS SDK for Python (Boto3)&lt;/a&gt;. There’s also &lt;a href=&quot;https://www.youtube.com/watch?v=eM8uoGJO2AI&quot;&gt;a video available&lt;/a&gt;! This one was a real lifesaver for me to understand how all of this works. Thank you, Kyle!&lt;/p&gt;
&lt;h2 id=&quot;a-boto3-event-handler-for-gzipping-requests&quot;&gt;A &lt;code&gt;boto3&lt;/code&gt; event handler for gzipping requests&lt;/h2&gt;
&lt;p&gt;At this point, we know enough to understand how we can add the gzip behavior to our CloudWatch &lt;code&gt;PutMetricData&lt;/code&gt; requests.&lt;/p&gt;
&lt;p&gt;Let’s update our test example and add a custom event listener:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; boto3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; gzip&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;endpoint_url = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;http://localhost:8000/&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;cw_client = boto3.client(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;cloudwatch&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;endpoint_url&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=endpoint_url, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;use_ssl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;False&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;event_system = cw_client.meta.events&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# Gzip handler&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;gzip_request_body&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;kwargs&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;gzipped_body = gzip.compress(request.body)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;request.headers.add_header(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Content-Encoding&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;gzip&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;request.data = gzipped_body&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# registers the custom handler&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;event_system.register(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;before-sign.cloudwatch.PutMetricData&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, gzip_request_body)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;response = cw_client.put_metric_data(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;MetricData&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;MetricName&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;TEST_BOTO&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Dimensions&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Name&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;APP_VERSION&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                    &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Value&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;1.0&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Unit&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;None&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Value&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;17&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;Namespace&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;BotoTest&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(response)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import boto3import gzipendpoint_url = &amp;#x22;http://localhost:8000/&amp;#x22;cw_client = boto3.client(&amp;#x27;cloudwatch&amp;#x27;,  endpoint_url=endpoint_url, use_ssl=False)event_system = cw_client.meta.events# Gzip handlerdef gzip_request_body(request, **kwargs):    gzipped_body = gzip.compress(request.body)    request.headers.add_header(&amp;#x27;Content-Encoding&amp;#x27;, &amp;#x27;gzip&amp;#x27;)    request.data = gzipped_body# registers the custom handlerevent_system.register(&amp;#x27;before-sign.cloudwatch.PutMetricData&amp;#x27;, gzip_request_body)response = cw_client.put_metric_data(    MetricData = [        {            &amp;#x27;MetricName&amp;#x27;: &amp;#x27;TEST_BOTO&amp;#x27;,            &amp;#x27;Dimensions&amp;#x27;: [                {                    &amp;#x27;Name&amp;#x27;: &amp;#x27;APP_VERSION&amp;#x27;,                    &amp;#x27;Value&amp;#x27;: &amp;#x27;1.0&amp;#x27;                },            ],            &amp;#x27;Unit&amp;#x27;: &amp;#x27;None&amp;#x27;,            &amp;#x27;Value&amp;#x27;: 17        },    ],    Namespace=&amp;#x27;BotoTest&amp;#x27;)print(response)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note that we are using the &lt;code&gt;before-sign&lt;/code&gt; event type because we want to alter the request before the signature is applied to the request.&lt;/p&gt;
&lt;p&gt;If we run this code and check our debug web server we will see something like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Boto3 sending gzipped requests using a custom event handler&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;598&quot; src=&quot;https://loige.co/_astro/boto3-with-gzip-compression.CukyWMG8_ZqQC2u.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Now the requests are compressed! We are sending exactly the same request as before and now it’s sending only &lt;strong&gt;151 bytes&lt;/strong&gt; as opposed to &lt;strong&gt;265 bytes&lt;/strong&gt; from the original request!&lt;/p&gt;
&lt;p&gt;That’s some pretty good compression!&lt;/p&gt;
&lt;p&gt;Of course, your mileage might vary depending on the shape of your custom metrics. Figuring out how much data can you actually pack in 40 KB might take a little bit of research. Keep in mind you are still limited to 20 metrics per request and 10 dimensions per metric. Gzipping is only increasing your chances to stay within boundaries if you really have to use a lot of dimensions (maybe with long names) or if you have a lot of values per metric.&lt;/p&gt;
&lt;p&gt;Now, if we remove the configuration for &lt;code&gt;endpoint_url&lt;/code&gt; and send the request to AWS, we can see that everything still works and that the compressed request is processed correctly:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Cloudwatch custom metrics dashboard with data sent from boto3&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;498&quot; src=&quot;https://loige.co/_astro/cloudwatch-metrics-dashboard-from-boto3.pOz6PtDf_Z1wNvST.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Success!&lt;/p&gt;
&lt;h2 id=&quot;a-few-ideas-for-more-defensive-solutions&quot;&gt;A few ideas for more defensive solutions&lt;/h2&gt;
&lt;p&gt;Compressing the payload for &lt;code&gt;PutMetricData&lt;/code&gt; requests is not an absolute guarantee that we won’t be exceeding the 40 KB payload limit. Gzip certainly helps, but you might still bump into the limit and have failures in your application.&lt;/p&gt;
&lt;p&gt;If you want to be &lt;em&gt;failure-proof&lt;/em&gt; ™️, here are some ideas that we explored with our colleagues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Optimistic solution: Try the request and catch potential exceptions. If you see the &lt;code&gt;PutMetricData&lt;/code&gt; failed because the payload is too large, just split all the data into 2 requests.&lt;/li&gt;
&lt;li&gt;Pessimistic solution: pre-compute the gzipped payload before sending the request and if that’s bigger than 40 KB, then split the request into 2 parts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The pessimistic solution has the disadvantage that you will be gzipping the payload twice (before you create the request to make sure it’s within boundaries and then in your event handler), but it will avoid sending invalid requests upfront.&lt;/p&gt;
&lt;p&gt;Right now, we haven’t implemented any of these strategies. In our case, these metrics are not business-critical and we can afford some sparse failure, so we preferred to keep the code as simple as possible.&lt;/p&gt;
&lt;p&gt;If, later on, we will observe production errors, then it might be worth applying one of these strategies. I am more in favor of the optimistic approach because I expect it will be pretty rare to bump into this limit.&lt;/p&gt;
&lt;p&gt;What do you think, which strategy would you apply? Do you have other ideas? let me know that in the comments box below! 😁&lt;/p&gt;
&lt;h2 id=&quot;extensibility-in-the-aws-sdk&quot;&gt;Extensibility in the AWS SDK&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: It turns out that also with other languages like PHP, Go and JavaScript, the AWS SDK offers some degree of extensibility that should allow you to accomplish something similar to what was discussed in this post.&lt;/p&gt;
&lt;p&gt;If you are using any of these other languages you can consult the following resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.github.io/aws-sdk-go-v2/docs/middleware/&quot;&gt;Customizing the AWS SDK for Go V2 Client Requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/developer/middleware-stack-modular-aws-sdk-js/&quot;&gt;Introducing Middleware Stack in Modular AWS SDK for JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/guide_handlers-and-middleware.html&quot;&gt;Handlers and Middleware in the AWS SDK for PHP Version 3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks a lot to the following (amazing) people at AWS for helping me to find out this information in the huge haystack that is the AWS documentation: &lt;a href=&quot;https://twitter.com/danilop&quot;&gt;Danilo Poccia&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/heitor_lessa&quot;&gt;Heitor Lessa&lt;/a&gt;, and &lt;a href=&quot;https://twitter.com/trivikram&quot;&gt;Trivikram&lt;/a&gt;. You rock! 🤘&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The event system in &lt;code&gt;boto3&lt;/code&gt; is pretty powerful and it allows you to customize the default behavior of how clients will send HTTP requests to AWS.&lt;/p&gt;
&lt;p&gt;In this article, we saw how that can be useful for inspecting how AWS APIs are actually used or to add additional functionality that isn’t supported out of the box (e.g. gzipping the HTTP payload of outgoing requests).&lt;/p&gt;
&lt;p&gt;If you found this article useful &lt;a href=&quot;https://twitter.com/loige&quot;&gt;consider following me on Twitter&lt;/a&gt; and feel more than welcome to leave a comment below. I’d be really curious to find out what was your use case and if this article helped you out.&lt;/p&gt;
&lt;p&gt;A huge “thank you” goes to my colleague &lt;a href=&quot;https://twitter.com/martinbpeters&quot;&gt;Martin&lt;/a&gt; for involving me in this piece of work (and indirectly for dragging me into this rabbit hole 🐇)! Also thanks to &lt;a href=&quot;https://twitter.com/eoins&quot;&gt;Eoin Shanaghy&lt;/a&gt; for kindly reviewing this article! Finally, thanks to &lt;a href=&quot;https://twitter.com/benbridts&quot;&gt;Ben Bridts&lt;/a&gt; for reporting an error in one of the examples! 🙏&lt;/p&gt;
&lt;p&gt;See you soon! 👋&lt;/p&gt;
&lt;h3 id=&quot;about-fourtheorem&quot;&gt;About fourTheorem&lt;/h3&gt;
&lt;p&gt;If you want to know more about &lt;a href=&quot;https://www.fourtheorem.com/&quot;&gt;fourTheorem&lt;/a&gt;, we are a team of business-focused technologists that deliver. We have been helping a dozen companies to get the best out of AWS and we had a lot of fun while doing that. If you are curious to know more about what we do you can check out some of our &lt;a href=&quot;https://www.fourtheorem.com/case-studies&quot;&gt;case studies&lt;/a&gt; and our &lt;a href=&quot;https://www.fourtheorem.com/customers&quot;&gt;customer success stories&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you would like to work with us, don’t be shy, &lt;a href=&quot;https://www.fourtheorem.com/contact&quot;&gt;we’d love to get in touch with you&lt;/a&gt;! 🙂&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/how-to-send-gzipped-requests-with-boto3.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/how-to-send-gzipped-requests-with-boto3.png" width="1200" height="630"/></media:content><category>python</category><category>aws</category><author>Luciano Mammino</author><comments>https://loige.co/how-to-send-gzipped-requests-with-boto3/#comments</comments><enclosure url="https://loige.co/og/how-to-send-gzipped-requests-with-boto3.png" length="0" type="image/png"/></item><item><title>Fastify and Preact for quick web app prototyping</title><link>https://loige.co/fastify-and-preact-for-quick-web-app-prototyping/</link><guid isPermaLink="true">https://loige.co/fastify-and-preact-for-quick-web-app-prototyping/</guid><description>This article shows how to quickly build web app prototypes using Fastify for the backend API and Preact for the frontend UI. It also covers how to dockerize the app for easy sharing. Key points are the plugin architecture of Fastify, the lightweight nature of Preact, and the use of htm for defining UI without transpilation.</description><pubDate>Mon, 18 Feb 2019 20:22:58 GMT</pubDate><content:encoded>&lt;p&gt;In this article I will show my setup to build and share web apps prototypes using &lt;strong&gt;Fastify&lt;/strong&gt; and &lt;strong&gt;Preact&lt;/strong&gt;, two technologies that I love.&lt;/p&gt;
&lt;p&gt;I will also use &lt;strong&gt;htm&lt;/strong&gt;, a library that can be easily integrated with Preact to define DOM elements in a very expressive and react-like way (like &lt;em&gt;JSX&lt;/em&gt;), without having to use &lt;em&gt;transpilers&lt;/em&gt; like Babel. Finally we will see how to &lt;em&gt;dockerize&lt;/em&gt; a sample app built with this setup. This will make the app easy to share with co-workers and friends.&lt;/p&gt;
&lt;p&gt;I came up with this stack, few weeks ago when I had to build a very simple prototype web application to test some product assumptions with some co-workers.&lt;/p&gt;
&lt;p&gt;My experiment was quite successful. I was able to build my prototype quickly and it was super easy for my colleagues to play with it and give me feedback, even if they didn’t have Node.js and NPM installed on their machines.&lt;/p&gt;
&lt;p&gt;For these reasons, I think this approach is probably worth sharing and I look forward to receiving your feedback in case you decide to give this tech stack a try.&lt;/p&gt;
&lt;h2 id=&quot;tldr&quot;&gt;TLDR;&lt;/h2&gt;
&lt;p&gt;If you know already &lt;strong&gt;Fastify&lt;/strong&gt; and &lt;strong&gt;Preact&lt;/strong&gt; and you are just looking for a quick way to get started with a stack based on these 2 technologies… well you just have to run the following commands:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;clone&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;https://github.com/lmammino/fastify-preact-htm-boilerplate.git&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;my-new-project&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;my-new-project&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;rm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-rf&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;.git&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;install&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;git clone https://github.com/lmammino/fastify-preact-htm-boilerplate.git my-new-projectcd my-new-projectrm -rf .gitnpm install&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Of course, you can replace &lt;code&gt;my-new-project&lt;/code&gt; with the actual name of your project.&lt;/p&gt;
&lt;p&gt;Now enjoy editing the sample code in src:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/ui&lt;/code&gt;: is for your frontend (Preact + htm)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/server&lt;/code&gt;: is for your backend (Fastify)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then run your project with:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;start&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm start&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And finally test it on &lt;code&gt;localhost:3000&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Oh, yeah… most importantly, don’t forget to &lt;a href=&quot;https://github.com/lmammino/fastify-preact-htm-boilerplate&quot;&gt;give me a ⭐️ on GitHub&lt;/a&gt; (pleazeee 😇)!&lt;/p&gt;
&lt;h2 id=&quot;fastify&quot;&gt;Fastify&lt;/h2&gt;
&lt;p&gt;If you never heard about &lt;strong&gt;Fastify&lt;/strong&gt;, it is a fast and low overhead web framework for Node.js.&lt;/p&gt;
&lt;p&gt;Fastify was initially created by &lt;a href=&quot;https://github.com/delvedor&quot;&gt;Tomas Della Vedova&lt;/a&gt; and &lt;a href=&quot;https://github.com/mcollina&quot;&gt;Matteo Collina&lt;/a&gt;. Today, it counts a core team of 10 developers, more than 130 contributors and almost 10.000 stars on GitHub.&lt;/p&gt;
&lt;p&gt;Fastify takes inspiration from Node.js frameworks that have been around for a while like &lt;strong&gt;Express&lt;/strong&gt; or &lt;strong&gt;Hapi&lt;/strong&gt;, but puts particular focus on performance, developer experience and composability. One of my favorite features is in fact the composable plugin system.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.fastify.io/docs/&quot;&gt;official Fastify documentation&lt;/a&gt; is a great place to start from, if you want to find out more about this wonderful framework.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Full disclosure&lt;/em&gt;: I am a member of the core team and I mostly contribute with building and maintaining the Fastify website and its documentation.&lt;/p&gt;
&lt;h2 id=&quot;preact&quot;&gt;Preact&lt;/h2&gt;
&lt;p&gt;If you never heard about &lt;strong&gt;Preact&lt;/strong&gt;, it is a UI library for the web, initially created as a lighter and faster drop-in alternative to React by &lt;a href=&quot;https://github.com/developit&quot;&gt;Jason Miller&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The project has been quite successful. It is now maintained by a &lt;a href=&quot;https://github.com/developit/preact/graphs/contributors&quot;&gt;team of contributors&lt;/a&gt; and has gained more than 20.000 GitHub stars.&lt;/p&gt;
&lt;p&gt;One of the reasons why I like Preact, is that it has a pluggable view definition layer. Normally you would use it with &lt;strong&gt;JSX&lt;/strong&gt; in combination with &lt;strong&gt;Babel&lt;/strong&gt; for transpilation, but if you don’t want to setup Babel and have a build process, you can use Preact in combination with &lt;a href=&quot;https://github.com/developit/htm&quot;&gt;&lt;strong&gt;htm&lt;/strong&gt;&lt;/a&gt;, which uses template literals and doesn’t require any transpilation on modern browsers.&lt;/p&gt;
&lt;p&gt;We are going to use htm in this article, so hold your horses… you’ll see some examples soon!&lt;/p&gt;
&lt;h2 id=&quot;project-overview&quot;&gt;Project overview&lt;/h2&gt;
&lt;p&gt;So, you decided to follow along and build this stack from scratch, very well!&lt;/p&gt;
&lt;p&gt;Our goal will be to build a simple web app that displays the server time at startup.&lt;/p&gt;
&lt;p&gt;Just to give you a more concrete idea, this is more or less how it is going to look when completed:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Sample server time web application&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;738&quot; height=&quot;462&quot; src=&quot;https://loige.co/_astro/sample-server-time-app.Blsaf-31_25ye74.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;This is a Single Page Application (SPA) where Preact and htm are used to build the fronted App, while Fastify is used to build the &lt;em&gt;server time API&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;By the way, the meticoulus reader might have noticed that amazing favicon there. Stop squinting, here’s a zoomed-in version, just for your personal enjoyment!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Cheeta grimage&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;256&quot; height=&quot;256&quot; src=&quot;https://loige.co/_astro/cheeta-grimace.Di6bAvt8_1mWLVt.webp&quot; &gt;&lt;/p&gt;
&lt;h2 id=&quot;backend-setup&quot;&gt;Backend setup&lt;/h2&gt;
&lt;p&gt;Ok, let’s start by creating a new folder:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;server-time&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;server-time&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;mkdir server-timecd server-time&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now we can initialize it as an NPM project and get Fastify installed.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-y&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--save&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;fastify@next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;fastify-static@next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;fastify-cli&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm init -ynpm i --save fastify@next fastify-static@next fastify-cli&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Notice that I am using &lt;code&gt;@next&lt;/code&gt; for some dependencies to get Fastify v2, currently in release candidate stage, but that should become the main stable version very soon!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: you can also create a new Fastify project using the Fastify CLI:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;fastify-cli&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;generate&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;server-time&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npx fastify-cli generate server-time&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;At the time of writing this will generate a new project for Fastify 1.x, but it will be updated soon, once v2 will be released as stable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let’s analyze the installed packages one by one:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fastify&lt;/code&gt; is the core component of the framework&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fastify-static&lt;/code&gt; is an optional plugin that allows you to easily serve static files from a Fastify server&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fastify-cli&lt;/code&gt; is a command line integration that allows you to start your Fastify apps.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At this point we are ready to create our Fastify API, let’s place the server code in &lt;code&gt;src/server/server.js&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;path&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#AF4238&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#AF4238&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;fastify&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;opts&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// serves static assets from the `src/ui` folder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;fastify&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;fastify-static&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;), {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;root&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;join&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;__dirname&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;..&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ui&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Add your API endpoints here&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;fastify&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/api/time&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;reply&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;time&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Date&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;toISOString&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const path = require(&amp;#x27;path&amp;#x27;)module.exports = async function (fastify, opts) {  // serves static assets from the &amp;#x60;src/ui&amp;#x60; folder  fastify.register(require(&amp;#x27;fastify-static&amp;#x27;), {    root: path.join(__dirname, &amp;#x27;..&amp;#x27;, &amp;#x27;ui&amp;#x27;),  })  // Add your API endpoints here  fastify.get(&amp;#x27;/api/time&amp;#x27;, async (request, reply) =&gt; {    return { time: new Date().toISOString() }  })}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The code above should be quite self explanatory, but there are some interesting details to cover, especially if you are not familiar with Fastify.&lt;/p&gt;
&lt;p&gt;The first thing you might notice is the usage of the &lt;code&gt;async&lt;/code&gt; keyword. Fastify supports both the &lt;em&gt;async/await style&lt;/em&gt; and a more traditional &lt;em&gt;callback-based style&lt;/em&gt;, so you can pick your favorite flavor.&lt;/p&gt;
&lt;p&gt;Another interesting detail is that we are defining a server as an exported module. This module (a &lt;em&gt;plugin&lt;/em&gt; in Fastify lingo) is essentially a function that receives a Fastify instance (&lt;code&gt;fastify&lt;/code&gt;) and a set of options (&lt;code&gt;opts&lt;/code&gt;) as arguments. Inside the module definition we can use the &lt;code&gt;fastify&lt;/code&gt; instance to register plugins, as we are doing here with the &lt;code&gt;fastify-static&lt;/code&gt;, or add HTTP endpoints using methods such as &lt;code&gt;fastify.get&lt;/code&gt; or &lt;code&gt;fastify.post&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This module approach, while a bit unconventional, has its perks. First of all, it allows you to compose different servers together. Imagine you have created a server to manage a blog and one to manage a forum, you could easily embed them in an existing app and mount them over paths like &lt;code&gt;/blog&lt;/code&gt; and &lt;code&gt;/forum&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Moreover, this approach keeps your apps and sub-apps abstract from the actual server bootstrapping (socket binding and listening), which is left either to a root level app or to the &lt;code&gt;fastify-cli&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let’s see how to do that with the fastify Command Line Interface:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;node_modules/.bin/fastify&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--log-level&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;info&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;src/server/server.js&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;node_modules/.bin/fastify start --log-level info src/server/server.js&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;For simplicity we can add this command to our &lt;code&gt;package.json&lt;/code&gt; scripts:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;start&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;fastify start --log-level info src/server/server.js&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{  &amp;#x22;scripts&amp;#x22;: {    &amp;#x22;start&amp;#x22;: &amp;#x22;fastify start --log-level info src/server/server.js&amp;#x22;  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Before launching the server, we have to make sure our UI assets folder exists (fastify-static would crash otherwise), so let’s create it:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;src/ui&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;mkdir src/ui&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now we can run our app with &lt;code&gt;npm start&lt;/code&gt; and point our browser to &lt;a href=&quot;http://localhost:3000/api/time&quot;&gt;localhost:3000/api/time&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You should now see a response like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;2019-02-17T19:32:03.354Z&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{ &amp;#x22;time&amp;#x22;: &amp;#x22;2019-02-17T19:32:03.354Z&amp;#x22; }&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;At this point you are probably noticing another amazing feature of Fastify: JSON serialization is handled out of the box if a route returns an object.&lt;/p&gt;
&lt;p&gt;Hooray, our server API is now implemented. 🥳&lt;/p&gt;
&lt;p&gt;Let’s move on and let’s start to work on the frontend!&lt;/p&gt;
&lt;h2 id=&quot;frontend-setup&quot;&gt;Frontend setup&lt;/h2&gt;
&lt;p&gt;All our frontend code will live in &lt;code&gt;src/ui&lt;/code&gt; and it will be made of 5 files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;app.js&lt;/code&gt;: the code for our Preact app&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bootstrap.min.css&lt;/code&gt;: the CSS code for styling our app (directly from the Bootstrap framework)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;favicon.ico&lt;/code&gt;: our delicious favicon, because you are not building a serious app if you don’t have a serious favicon!&lt;/li&gt;
&lt;li&gt;&lt;code&gt;index.html&lt;/code&gt;: main HTML code for our SPA&lt;/li&gt;
&lt;li&gt;&lt;code&gt;preacthtm.js&lt;/code&gt;: the code for Preact + htm.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First of all let’s download the files for Bootstrap, Preact and our favicon:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;https://unpkg.com/htm@2.0.0/preact/standalone.js&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;src/ui/preacthtm.js&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;src/ui/bootstrap.min.css&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;https://github.com/lmammino/fastify-preact-htm-boilerplate/blob/master/src/ui/favicon.ico?raw=true&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;src/ui/favicon.ico&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;curl &amp;#x22;https://unpkg.com/htm@2.0.0/preact/standalone.js&amp;#x22; &gt; src/ui/preacthtm.jscurl &amp;#x22;https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css&amp;#x22; &gt; src/ui/bootstrap.min.csscurl &amp;#x22;https://github.com/lmammino/fastify-preact-htm-boilerplate/blob/master/src/ui/favicon.ico?raw=true&amp;#x22; &gt; src/ui/favicon.ico&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now it’s time to create our &lt;code&gt;src/ui/index.html&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;!&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;doctype&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;lang&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;meta&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;charset&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;utf-8&quot;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;meta&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;viewport&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;width=device-width, initial-scale=1, shrink-to-fit=no&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;/&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;&amp;#x3C;!-- Bootstrap CSS --&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;rel&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;/bootstrap.min.css&quot;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;My awesome server time&lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;app&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;&amp;#x3C;!-- JavaScript --&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;/preacthtm.js&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;/app.js&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;!doctype html&gt;&lt;html lang=&amp;#x22;en&amp;#x22;&gt;  &lt;head&gt;    &lt;meta charset=&amp;#x22;utf-8&amp;#x22; /&gt;    &lt;meta      name=&amp;#x22;viewport&amp;#x22;      content=&amp;#x22;width=device-width, initial-scale=1, shrink-to-fit=no&amp;#x22;    /&gt;    &lt;!-- Bootstrap CSS --&gt;    &lt;link rel=&amp;#x22;stylesheet&amp;#x22; href=&amp;#x22;/bootstrap.min.css&amp;#x22; /&gt;    &lt;title&gt;My awesome server time&lt;/title&gt;  &lt;/head&gt;  &lt;body&gt;    &lt;div id=&amp;#x22;app&amp;#x22;&gt;&lt;/div&gt;    &lt;!-- JavaScript --&gt;    &lt;script src=&amp;#x22;/preacthtm.js&amp;#x22;&gt;&lt;/script&gt;    &lt;script src=&amp;#x22;/app.js&amp;#x22;&gt;&lt;/script&gt;  &lt;/body&gt;&lt;/html&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This is a pretty standard HTML 5 page where we are loading all our resources (CSS and JS) and creating an empty &lt;code&gt;div&lt;/code&gt; (&lt;code&gt;id=&quot;app&quot;&lt;/code&gt;) where we will mount our frontend application at runtime.&lt;/p&gt;
&lt;p&gt;Let’s now look at the code needed for our app in &lt;code&gt;src/ui/app.js&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/* global htmPreact */&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;render&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;htmPreact&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;App&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Component&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;componentDidMount&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;setState&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;loading&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;time&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fetch&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/api/time&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;setState&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;loading&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;time&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;time&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; }))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;render&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;div class=&quot;container mt-5&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;div class=&quot;row justify-content-center&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;div class=&quot;col&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;h1&gt;Hello from your new App&amp;#x3C;/h1&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;div&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#387138&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;loading&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#387138&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#387138&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;` &amp;#x3C;p&gt;😴 Loading time from server...&amp;#x3C;/p&gt; `&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#387138&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;time&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#387138&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;` &amp;#x3C;p&gt;⏱ Time from server: &amp;#x3C;i&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#387138&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;time&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;/i&gt;&amp;#x3C;/p&gt; `&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;/div&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;hr /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;div&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;👩‍💻 Have fun changing the code from this boilerplate:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;ul&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;li&gt;UI code available at &amp;#x3C;code&gt;/src/ui&amp;#x3C;/code&gt;&amp;#x3C;/li&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;li&gt;Server-side code available at &amp;#x3C;code&gt;/src/server&amp;#x3C;/code&gt;&amp;#x3C;/li&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;/ul&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;/div&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;/div&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;/div&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;/div&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;render&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;` &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;App&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt; /&gt; `&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getElementById&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;app&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;/* global htmPreact */const { html, Component, render } = htmPreactclass App extends Component {  componentDidMount() {    this.setState({ loading: true, time: null })    fetch(&amp;#x27;/api/time&amp;#x27;)      .then((response) =&gt; response.json())      .then((data) =&gt; this.setState({ loading: false, time: data.time }))  }  render(props, state) {    return html&amp;#x60;      &lt;div class=&amp;#x22;container mt-5&amp;#x22;&gt;        &lt;div class=&amp;#x22;row justify-content-center&amp;#x22;&gt;          &lt;div class=&amp;#x22;col&amp;#x22;&gt;            &lt;h1&gt;Hello from your new App&lt;/h1&gt;            &lt;div&gt;              ${state.loading &amp;#x26;&amp;#x26; html&amp;#x60; &lt;p&gt;😴 Loading time from server...&lt;/p&gt; &amp;#x60;} ${state.time &amp;#x26;&amp;#x26;              html&amp;#x60; &lt;p&gt;⏱ Time from server: &lt;i&gt;${state.time}&lt;/i&gt;&lt;/p&gt; &amp;#x60;}            &lt;/div&gt;            &lt;hr /&gt;            &lt;div&gt;              👩‍💻 Have fun changing the code from this boilerplate:              &lt;ul&gt;                &lt;li&gt;UI code available at &lt;code&gt;/src/ui&lt;/code&gt;&lt;/li&gt;                &lt;li&gt;Server-side code available at &lt;code&gt;/src/server&lt;/code&gt;&lt;/li&gt;              &lt;/ul&gt;            &lt;/div&gt;          &lt;/div&gt;        &lt;/div&gt;      &lt;/div&gt;    &amp;#x60;  }}render(html&amp;#x60; &lt;${App} /&gt; &amp;#x60;, document.getElementById(&amp;#x27;app&amp;#x27;))&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In our frontend app we have only one stateful component called &lt;code&gt;App&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The state for this component is defined by 2 variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;loading&lt;/code&gt;: a boolean flag used to indicate whether an API request to fetch the current server time is in progress&lt;/li&gt;
&lt;li&gt;&lt;code&gt;time&lt;/code&gt;: a string that contains the last fetched time&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have familiarity with React, the component should be pretty straightforward to understand.&lt;/p&gt;
&lt;p&gt;By using Preact and htm, we can create a component by writing a class that extends from the built in &lt;code&gt;Component&lt;/code&gt; class.&lt;/p&gt;
&lt;p&gt;In this class we can define the component behavior using lifecycle hooks like &lt;code&gt;componentDidMount&lt;/code&gt; and the look and feel using the &lt;code&gt;render&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;In our case, once the component is attached to the the page (&lt;code&gt;componentDidMount&lt;/code&gt; hook), we set the state as &lt;code&gt;loading&lt;/code&gt; and we issue a request to our time API, using &lt;code&gt;fetch&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Once the request is completed, we set the &lt;code&gt;time&lt;/code&gt; and reset the &lt;code&gt;loading&lt;/code&gt; state to false.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;render&lt;/code&gt; function is automatically invoked every time the component state or its props change. In this method we define the DOM for the component using htm.&lt;/p&gt;
&lt;p&gt;htm allows us to define the DOM nodes using tagged template literals with the special tag &lt;code&gt;html&lt;/code&gt;. Within our template literal, we can have dynamic expressions, like the ones we use to check the state and decide what to render in case of loading or not.&lt;/p&gt;
&lt;p&gt;One last detail, aside from defining the behavior and the look and feel of our App component we have to create an instance and render it in our HTML page.&lt;/p&gt;
&lt;p&gt;We do that by using the &lt;code&gt;render&lt;/code&gt; function from the global &lt;code&gt;htmPreact&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;That’s it.&lt;/p&gt;
&lt;p&gt;Relaunch your server and visit &lt;a href=&quot;http://localhost:3000&quot;&gt;localhost:3000&lt;/a&gt; to see the app in action!&lt;/p&gt;
&lt;p&gt;Feel free to play around, change and break things, until you are happy enough with the outcome and feel ready to share your creation with the world (or maybe with just some friends).&lt;/p&gt;
&lt;h2 id=&quot;dockerize-all-the-things&quot;&gt;Dockerize all the things&lt;/h2&gt;
&lt;p&gt;In my opinion, the best way to share your new little project is to use Docker.&lt;/p&gt;
&lt;p&gt;With Docker, whoever is trying to run your app doesn’t have to worry about having the right versions of Node.js and NPM and to run the right sequence of commands to install dependencies and run the server.&lt;/p&gt;
&lt;p&gt;In order to “dockerize” our app we have to create a very simple &lt;code&gt;Dockerfile&lt;/code&gt; in the root folder of our project:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;docker&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; node:11-alpine&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;WORKDIR&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; /app&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;COPY&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; . /app&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; npm install --production&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;EXPOSE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; 3000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;CMD&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;npm&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;start&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;FROM node:11-alpineWORKDIR /appCOPY . /appRUN npm install --productionEXPOSE 3000CMD [&amp;#x22;npm&amp;#x22;, &amp;#x22;start&amp;#x22;]&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;With this setup we are essentially doing the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creating an image starting from the the latest version of Node.js 11, linux alpine.&lt;/li&gt;
&lt;li&gt;Everything from our current folder is copied inside &lt;code&gt;/app&lt;/code&gt; inside the container.&lt;/li&gt;
&lt;li&gt;At this point we run &lt;code&gt;npm install&lt;/code&gt; to make sure that all the dependencies are downloaded and installed. The &lt;code&gt;--production&lt;/code&gt; flag will make so that only production dependencies are installed, speeding up the image creation in case you have many dev dependencies.&lt;/li&gt;
&lt;li&gt;We also expose port 3000, which is where our web server will run by default.&lt;/li&gt;
&lt;li&gt;Finally, we define our runtime command as &lt;code&gt;npm start&lt;/code&gt; to start the application.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In order to build the image for this container, you can run the following command:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-t&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;server-time&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;docker build -t server-time .&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;After few second the image should be ready and you should be able to run containers off of it:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-it&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-p&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;3000:3000&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;server-time&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;docker run -it -p 3000:3000 server-time&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;-p&lt;/code&gt; parameter allows you to map the port 3000 from within the container to the local port 3000, so that you can access the dockerized application from &lt;code&gt;localhost:3000&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now you are ready to share this application. Whoever is receiving it has to have Docker installed and run the two commands above!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, I showed you how easy it is to bootstrap a quick web app development environment using Fastify and Preact. We also saw how to share the resulting app with Docker.&lt;/p&gt;
&lt;p&gt;I said that this setup is ideal for building quick prototypes, so you are maybe wondering what’s missing in case you want to take the app to production.&lt;/p&gt;
&lt;p&gt;Well, these are probably some of the concerns you will have when starting to think about making your code production ready:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Frontend assets compilation: how to create optimized (bundled) files, maybe by using Webpack, Babel or other similar tools.&lt;/li&gt;
&lt;li&gt;Frontend routing&lt;/li&gt;
&lt;li&gt;Server side rendering&lt;/li&gt;
&lt;li&gt;Data persistence&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I didn’t cover all these aspects with my setup yet, so I don’t want to consider this production ready, but I am quite sure you can expand it and cover the missing pieces and be able to build production ready apps with Fastify and Preact.&lt;/p&gt;
&lt;p&gt;I hope this article was informative and that this stack will be useful to you for your next prototype application.&lt;/p&gt;
&lt;p&gt;This article was possible only because of the support and the kind reviews of some developers I really admire, so &lt;strong&gt;thank you to them all&lt;/strong&gt; (in alphabetical order) 😻:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/AngeloGulina&quot;&gt;Angelo Gulina&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/developit&quot;&gt;Jason Miller&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/marvinhagemeister&quot;&gt;Marvin Hagemeister&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mcollina&quot;&gt;Matteo Collina&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/delvedor&quot;&gt;Tomas Della Vedova&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I really look forward to hearing your feedback, so please don’t hesitate leaving a comment below!&lt;/p&gt;
&lt;p&gt;Until next time, ciao 👋&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/fastify-and-preact-for-quick-web-app-prototyping.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/fastify-and-preact-for-quick-web-app-prototyping.png" width="1200" height="630"/></media:content><category>javascript</category><category>node-js</category><category>fastify</category><category>react</category><category>docker</category><author>Luciano Mammino</author><comments>https://loige.co/fastify-and-preact-for-quick-web-app-prototyping/#comments</comments><enclosure url="https://loige.co/og/fastify-and-preact-for-quick-web-app-prototyping.png" length="0" type="image/png"/></item><item><title>A random emoji in your terminal prompt. How and Why!</title><link>https://loige.co/random-emoji-in-your-prompt-how-and-why/</link><guid isPermaLink="true">https://loige.co/random-emoji-in-your-prompt-how-and-why/</guid><description>Customize your terminal prompt with Bash PS1 variable and RANDOM function to show a random emoji on each command. Learn Bash arrays, escape sequences, and functions. Emojis make your terminal more fun and keep your morale up during debugging.</description><pubDate>Mon, 17 Dec 2018 18:50:00 GMT</pubDate><content:encoded>&lt;p&gt;In this article, we will see how to customize our terminal prompt and add a random emoji in it.&lt;/p&gt;
&lt;p&gt;This is my terminal prompt:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;My terminal prompt with random emojis&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;922&quot; height=&quot;664&quot; src=&quot;https://loige.co/_astro/my-terminal.s6Ov4dlf_2n0y3M.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;If I could have a penny every time somebody asked me how did I put a random emoji in there, well… I wouldn’t probably be a millionaire, but I would definitely be able to afford few more coffees every day and be less sleepy 😴!&lt;/p&gt;
&lt;p&gt;In this article I’ll explain how I &lt;em&gt;emojified&lt;/em&gt; my terminal and, since it is very simple stuff, I’ll also try to explore some extra details on how to customize your bash experience.&lt;/p&gt;
&lt;h2 id=&quot;bash-config&quot;&gt;Bash config&lt;/h2&gt;
&lt;p&gt;Bash customizations are generally made in a file saved in the user home directory. This file is generally called &lt;code&gt;.bashrc&lt;/code&gt; &lt;del&gt;(more common on Linux systems)&lt;/del&gt; or &lt;code&gt;.bash_profile&lt;/code&gt; &lt;del&gt;(more common on MacOS)&lt;/del&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: &lt;code&gt;.bash_profile&lt;/code&gt; is executed for login shells, and &lt;code&gt;.bashrc&lt;/code&gt; is executed for non-login shells. (Thanks to &lt;a href=&quot;https://lobste.rs/u/colonelpanic&quot;&gt;@colonelpanic&lt;/a&gt; for the correction here).&lt;/p&gt;
&lt;p&gt;This file is essentially a Bash script file that gets loaded every single time you open a terminal session.&lt;/p&gt;
&lt;p&gt;Here’s an example of a possible &lt;code&gt;.bashrc&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# Source global definitions&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [ -f /etc/bashrc ]; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;then&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/etc/bashrc&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;fi&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# various command shortcuts&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;alias&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;og&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ls -ogrt&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;alias&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ls -al&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;alias&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;lc&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ls -C&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;alias&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;dir&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ls -lrt&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# in case you are a MS-DOS lover :P&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;alias&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;h&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;history&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;alias&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;pwd -P&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# shows the &quot;real&quot; path in bash, not the path via symlinks&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;alias&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;et&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;emacs-tty&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;alias&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;python&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=python2.7&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# environment&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;PS1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;[\u@\h \W]$ &apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# Set the command prompt!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;HOST&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;uname&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-n&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;EDITOR&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;vim&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;PATH&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$HOME&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;bin&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;/:&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$PATH&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;if [ -f /etc/bashrc ]; then  . /etc/bashrcfialias og=&amp;#x27;ls -ogrt&amp;#x27;alias ll=&amp;#x27;ls -al&amp;#x27;alias lc=&amp;#x27;ls -C&amp;#x27;alias dir=&amp;#x27;ls -lrt&amp;#x27; # in case you are a MS-DOS lover :Palias h=&amp;#x27;history&amp;#x27;alias p=&amp;#x27;pwd -P&amp;#x27;  # shows the &amp;#x22;real&amp;#x22; path in bash, not the path via symlinksalias et=&amp;#x27;emacs-tty&amp;#x27;alias python=python2.7export PS1=&amp;#x27;[\u@\h \W]$ &amp;#x27; # Set the command prompt!export HOST=&amp;#x60;uname -n&amp;#x60;export EDITOR=vimexport PATH=$HOME/bin/:$PATH&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;As you can see, this script has the only goal of setting up your bash environment. For instance, you can load other configuration files (here we load a global configuration if it is available). You can define shortcuts and aliases for common commands. Finally, you can export environment variables, for instance to define your default text editor or to modify/extend your &lt;code&gt;PATH&lt;/code&gt; (a list of directories where to look for executable commands).&lt;/p&gt;
&lt;h2 id=&quot;the-ps1-variable&quot;&gt;The PS1 variable&lt;/h2&gt;
&lt;p&gt;We briefly touched on &lt;code&gt;PATH&lt;/code&gt; and &lt;code&gt;EDITOR&lt;/code&gt;. There are many other &lt;em&gt;special&lt;/em&gt; variables in Bash that can be used to customize the look and feel and the behavior of your terminal.&lt;/p&gt;
&lt;p&gt;One of those variables (the most important in this article) is called &lt;code&gt;PS1&lt;/code&gt;. If I were a betting man, I would bet that the name stands for &lt;del&gt;&lt;code&gt;Prompt Style 1&lt;/code&gt;&lt;/del&gt; (&lt;strong&gt;Update 2020-04-18&lt;/strong&gt;: Rohit Chakraborty actually clarifies in the comments that &lt;strong&gt;PS1 stands for &lt;code&gt;Prompt String 1&lt;/code&gt;&lt;/strong&gt;!). &lt;code&gt;PS1&lt;/code&gt; allows you to define the look and feel of the primary bash prompt format.&lt;/p&gt;
&lt;p&gt;In the configuration example above we are defining the &lt;code&gt;PS1&lt;/code&gt; variable as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;PS1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;[\u@\h \W]$ &apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;export PS1=&amp;#x27;[\u@\h \W]$ &amp;#x27;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Which, in my personal laptop, renders like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Sample terminal bash prompt&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2188&quot; height=&quot;548&quot; src=&quot;https://loige.co/_astro/sample-prompt-style-example.DShGP5co_ZxNunf.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;At this point, you are probably already grasping how this works. The &lt;code&gt;PS1&lt;/code&gt; variable acts as a template, where special &lt;em&gt;escape sequences&lt;/em&gt; like &lt;code&gt;\u&lt;/code&gt; and &lt;code&gt;\h&lt;/code&gt; can be used to indicate &lt;em&gt;“replace this with my actual username (and hostname)”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;There are several sets of escape sequences that might be supported on different operative systems and different types of console, but here’s a list of the most common and widely supported escape sequences:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;\a&lt;/code&gt;: an ASCII bell character (07)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\d&lt;/code&gt; the date in “Weekday Month Date” format (e.g., “Tue May 26”)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\h&lt;/code&gt; the hostname up to the first `.’&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\H&lt;/code&gt; the full hostname&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\n&lt;/code&gt; newline&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\s&lt;/code&gt; the name of the shell, the basename of $0 (the portion following the final slash)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\t&lt;/code&gt; the current time in 24-hour HH:MM:SS format&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\T&lt;/code&gt; the current time in 12-hour HH:MM:SS format&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\@&lt;/code&gt; the current time in 12-hour am/pm format&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\u&lt;/code&gt; the username of the current user&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\w&lt;/code&gt; the current working directory&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\$&lt;/code&gt; if the effective UID is 0, a #, otherwise a $ (used to distinguish whether you are root or not)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\\&lt;/code&gt; a backslash&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\[&lt;/code&gt; begin a sequence of non-printing characters, which could be used to embed a terminal con­ trol sequence into the prompt&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\]&lt;/code&gt; end a sequence of non-printing characters&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For more comprehensive lists checkout:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/ANSI_escape_code&quot;&gt;ANSI escape code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://tldp.org/HOWTO/Bash-Prompt-HOWTO/bash-prompt-escape-sequences.html&quot;&gt;Bash Prompt Escape Sequences&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;👌 &lt;strong&gt;Pro tip&lt;/strong&gt;: There’s also a &lt;code&gt;PS2&lt;/code&gt; variable, which is the secondary prompt displayed when a command needs more input (e.g. a multi-line command). This is generally set as &lt;code&gt;PS2=&apos;&gt; &apos;&lt;/code&gt;.&lt;br&gt;
Also &lt;code&gt;PS3&lt;/code&gt; and &lt;code&gt;PS4&lt;/code&gt; exist. Funny enough this is not a pun to PlayStation players… If you are curious to know what they are used for, Archlinux has a great &lt;a href=&quot;https://wiki.archlinux.org/index.php/Bash/Prompt_customization#Prompts&quot;&gt;section on terminal prompts&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;the-random-variable&quot;&gt;The RANDOM variable&lt;/h2&gt;
&lt;p&gt;For our purpose, another useful Bash &lt;em&gt;special&lt;/em&gt; variable is &lt;code&gt;RANDOM&lt;/code&gt;. Its goal is very simple, as the name suggests, it always evaluate to a different random value.&lt;/p&gt;
&lt;p&gt;Try to run the following command multiple times to have a feeling for it:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$RANDOM&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;echo $RANDOM&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;I just ran this command 5 times and this is the list of outputs I got:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;31434&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;25704&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;32466&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;10374&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;29063&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To be more accurate, when using &lt;code&gt;$RANDOM&lt;/code&gt;, we are not referencing a constant value or a variable, but an internal Bash function that returns a &lt;em&gt;pseudorandom&lt;/em&gt; integer in the range &lt;code&gt;[0-32767]&lt;/code&gt; (both values included).&lt;/p&gt;
&lt;p&gt;This primitive is generally good enough when you need to do something random, like extracting an arbitrary element from an array.&lt;/p&gt;
&lt;p&gt;Be careful though because this technique is not strong enough for security sensitive situations like generating an encryption key.&lt;/p&gt;
&lt;p&gt;There are slightly more advanced use cases, for instance you might need to extract a random number over a smaller positive range. In such case you can use the &lt;em&gt;modulo operator&lt;/em&gt; and do something like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;SMALLER_RANDOM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;expr&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$RANDOM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;22&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$SMALLER_RANDOM&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;SMALLER_RANDOM=expr $RANDOM % 22echo $SMALLER_RANDOM&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This will print a number between &lt;code&gt;0&lt;/code&gt; (included) and &lt;code&gt;22&lt;/code&gt; (excluded).&lt;/p&gt;
&lt;p&gt;For other more advanced use cases check out the dedicated &lt;a href=&quot;http://tldp.org/LDP/abs/html/randomvar.html&quot;&gt;$RANDOM section in the &lt;strong&gt;Advanced Bash-Scripting Guide&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;bash-arrays&quot;&gt;Bash arrays&lt;/h2&gt;
&lt;p&gt;In Bash, an array is a variable containing multiple values. Any variable may be used as an array and there is no maximum limit to the size of an array.&lt;/p&gt;
&lt;p&gt;You can define an array in several different ways. You can assign the elements of an array one by one over different assignment statements:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;A&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;A&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;A&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;A[0]=1A[1]=2A[2]=3&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In a more generic fashion, you can assign a value in an given array index with the syntax &lt;code&gt;ARRAY[INDEX]=value&lt;/code&gt;, where &lt;code&gt;INDEX&lt;/code&gt; is an expression that is evaluated to a &lt;em&gt;non-negative integer&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Of course there is a shorter version that allows you to initialize an array with multiple elements with a single assignment instructions:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;A&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;A=(1 2 3)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;When you want to read (&lt;em&gt;dereference&lt;/em&gt;) a value out of an array you can do it this way:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--1:#AF4238&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;A&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[2]&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#AF4238&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;echo ${A[2]} # 3&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This will print &lt;code&gt;3&lt;/code&gt; as Bash arrays are &lt;em&gt;zero-indexed&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If you want to reference all the elements in the array you can do it as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--1:#AF4238&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;A&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[*]&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#AF4238&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# 1 2 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;echo ${A[*]} # 1 2 3&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--1:#AF4238&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;A&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[@]&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#AF4238&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# 1 2 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;echo ${A[@]} # 1 2 3&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The elements in an array can be also strings and you don’t need to wrap them in quotes (unless a string includes a space in it). For instance you can create the following array:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;SPORTS&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;Judo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;Jiu-jitsu&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Sicilian stick fighting&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;SPORTS=(Judo Jiu-jitsu &amp;#x27;Sicilian stick fighting&amp;#x27;)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;To loop over the elements of an array:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;SPORT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--1:#AF4238&quot;&gt;&lt;span style=&quot;--0:#CE9178&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;SPORTS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#AF4238&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$SPORT&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;done&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# prints:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;#&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# Judo&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# Jiu-jitsu&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# Sicilian stick fighting&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;for SPORT in &amp;#x22;${SPORTS[@]}&amp;#x22;do  echo $SPORTdone&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Finally, to get the length of an array you can use the following syntax:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#AF4238&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;SPORTS&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[@]&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#AF4238&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# 3 (notice the &quot;#&quot; before the variable name)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;echo ${#SPORTS[@]} # 3 (notice the &amp;#x22;#&amp;#x22; before the variable name)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;There is a lot more you can do with arrays. This is enough for what we want to achieve in this article, but if you are curious you can checkout the &lt;a href=&quot;http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_10_02.html&quot;&gt;array section in the &lt;strong&gt;Bash Beginners Guide&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;putting-it-all-together&quot;&gt;Putting it all together&lt;/h2&gt;
&lt;p&gt;Ok, now that we know about Bash config, Bash &lt;code&gt;PS1&lt;/code&gt; variable, Bash &lt;code&gt;RANDOM&lt;/code&gt; and Bash arrays, we have enough knowledge to be able to render a random emoji in our terminal prompt.&lt;/p&gt;
&lt;p&gt;Let’s try to write a simple &lt;code&gt;.bashrc&lt;/code&gt; file that can do that:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# .bashrc (or .bash_profile)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# declares an array with the emojis we want to support&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;EMOJIS&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;😺&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;😸&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;😹&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;😻&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;😼&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;😽&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;🙀&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;😿&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;😾&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# selects a random element from the EMOJIS set&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;SELECTED_EMOJI&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#AF4238&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;EMOJIS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$RANDOM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; % &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#AF4238&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;EMOJIS&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[@]&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#AF4238&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#AF4238&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# declare the terminal prompt format&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;PS1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;${SELECTED_EMOJI}  [\u@\h \W]$ &apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;EMOJIS=(😺 😸 😹 😻 😼 😽 🙀 😿 😾)SELECTED_EMOJI=${EMOJIS[$RANDOM % ${#EMOJIS[@]}]};export PS1=&amp;#x27;${SELECTED_EMOJI}  [\u@\h \W]$ &amp;#x27;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This will look as follows in my machine:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A terminal with the same emoji&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1844&quot; height=&quot;1328&quot; src=&quot;https://loige.co/_astro/random-emoji-in-terminal-wrong-implementation.B97o5trN_IhetH.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Well… as you can see there is something wrong with this… The emoji is always the same!&lt;/p&gt;
&lt;p&gt;The problem here is that &lt;code&gt;SELECTED_EMOJI&lt;/code&gt; gets computed only once when we open a new terminal window. At that point it behaves like a constant values, so our prompt will always look the same after that.&lt;/p&gt;
&lt;p&gt;With this approach we essentially end up with a random emoji per session, not per command!&lt;/p&gt;
&lt;p&gt;We can fix this by introducing a Bash function:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# .bashrc (or .bash_profile)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# declares an array with the emojis we want to support&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;EMOJIS&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;😺&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;😸&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;😹&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;😻&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;😼&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;😽&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;🙀&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;😿&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;😾&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# function that selects and return a random element from the EMOJIS set&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;RANDOM_EMOJI&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;SELECTED_EMOJI&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#AF4238&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;EMOJIS&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$RANDOM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; % &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#AF4238&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;EMOJIS&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[@]&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#AF4238&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#AF4238&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;$SELECTED_EMOJI&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# declare the terminal prompt format&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;PS1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;$(RANDOM_EMOJI)  [\u@\h \W]$ &apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;EMOJIS=(😺 😸 😹 😻 😼 😽 🙀 😿 😾)RANDOM_EMOJI() {  SELECTED_EMOJI=${EMOJIS[$RANDOM % ${#EMOJIS[@]}]};  echo $SELECTED_EMOJI;}export PS1=&amp;#x27;$(RANDOM_EMOJI)  [\u@\h \W]$ &amp;#x27;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Notice that we replaced &lt;code&gt;${SELECTED_EMOJI}&lt;/code&gt; with &lt;code&gt;$(RANDOM_EMOJI)&lt;/code&gt; in our terminal prompt template. Previously we were just interpolating a variable in our terminal prompt, now we are actually invoking a function that extracts a random emoji every single time the prompt is rendered.&lt;/p&gt;
&lt;p&gt;This is the new result:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A terminal full of random emoji cats&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1584&quot; height=&quot;698&quot; src=&quot;https://loige.co/_astro/some-random-cat-emojis-in-my-terminal-prompt.CbJ1Qkmy_Z1cS8b9.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Mission complete!&lt;/p&gt;
&lt;p&gt;But wait, not so quick! Let’s go over all the code once again to make sure we understand what’s going on behind the scenes.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;EMOJIS&lt;/code&gt; is just a simple array of strings, where every string is made up by just an emoji.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SELECTED_EMOJI&lt;/code&gt; inside our function &lt;code&gt;RANDOM_EMOJI&lt;/code&gt;, is a dynamic value that gets initialized to a random emoji from the set of supported emojis (&lt;code&gt;EMOJIS&lt;/code&gt;). This is the complicated part as it’s a &lt;em&gt;one-liner&lt;/em&gt; made up by different expressions on the right-hand side of the assignment. Let’s break it down:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;${#EMOJIS[@]}&lt;/code&gt; will be evaluated to the length of the &lt;code&gt;EMOJIS&lt;/code&gt; array&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$RANDOM % ${#EMOJIS[@]}&lt;/code&gt; will calculate a random integer and normalize it to the number of elements in the &lt;code&gt;EMOJIS&lt;/code&gt; array using the &lt;em&gt;modulo operator&lt;/em&gt;, so this is essentially extracting a random index for the &lt;code&gt;EMOJIS&lt;/code&gt; array.&lt;/li&gt;
&lt;li&gt;Finally we use the result of this expression to dereference a random element from the array and we assign it to &lt;code&gt;SELECTED_EMOJI&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pretty neat, right?&lt;/p&gt;
&lt;h2 id=&quot;bonus-bash-formatting&quot;&gt;Bonus: bash formatting&lt;/h2&gt;
&lt;p&gt;You probably noticed that my prompt (as well as most people prompt) comes with some fancy colors and other formatting wonders like bold and underlined text.&lt;/p&gt;
&lt;p&gt;Most terminals support different formatting options: bold, dim, underlined, blink, hidden, inverted and a number of different colors (for both background and foreground!).&lt;/p&gt;
&lt;p&gt;This is done by prefixing the text with some special escape sequences.&lt;/p&gt;
&lt;p&gt;To give you an example, let’s have a look at this code:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;My name is \033[32mLuciano\033[39m and my twitter handle is \033[1m@loige\033[21m&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;echo -e &amp;#x22;My name is \033[32mLuciano\033[39m and my twitter handle is \033[1m@loige\033[21m&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This will render as follows:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Formatted text in a Bash terminal&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2144&quot; height=&quot;530&quot; src=&quot;https://loige.co/_astro/formatted-text-in-bash-terminal.DqKDuCqE_ZQ4WWx.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;The way this works is by using a &lt;em&gt;special&lt;/em&gt; escape sequence, the &lt;code&gt;\033[&lt;/code&gt; prefix sequence. This sequence can be parameterized to indicate the start or the end of different formatting options. The generic syntax is &lt;code&gt;\033[_FormatCode_m&lt;/code&gt;, where &lt;code&gt;_FormatCode_&lt;/code&gt; will be replaced with some value to indicate different formatting options.&lt;/p&gt;
&lt;p&gt;In my previous example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;\033[32m&lt;/code&gt; stands for “start color green”&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\033[39m&lt;/code&gt; stands for “start default color (color reset)”&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\033[1m&lt;/code&gt; stands for “start emphasis (or bold)”&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\033[21m&lt;/code&gt; stands for “reset emphasis (or end bold)”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here is a table with different &lt;code&gt;_FormatCode_&lt;/code&gt; values and their effect.&lt;/p&gt;





























































































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;right&quot;&gt;&lt;code&gt;_FormatCode_&lt;/code&gt;&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;1&lt;/td&gt;&lt;td&gt;Bold&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;2&lt;/td&gt;&lt;td&gt;Dim&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;4&lt;/td&gt;&lt;td&gt;Underline&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;5&lt;/td&gt;&lt;td&gt;Blink&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;8&lt;/td&gt;&lt;td&gt;Hidden&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;0&lt;/td&gt;&lt;td&gt;Reset all&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;21&lt;/td&gt;&lt;td&gt;Reset bold&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;22&lt;/td&gt;&lt;td&gt;Reset dim&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;24&lt;/td&gt;&lt;td&gt;Reset underline&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;25&lt;/td&gt;&lt;td&gt;Reset blink&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;28&lt;/td&gt;&lt;td&gt;Reset hidden&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;39&lt;/td&gt;&lt;td&gt;Default color&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;30&lt;/td&gt;&lt;td&gt;Black&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;31&lt;/td&gt;&lt;td&gt;Red&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;32&lt;/td&gt;&lt;td&gt;Green&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;33&lt;/td&gt;&lt;td&gt;Yellow&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;34&lt;/td&gt;&lt;td&gt;Blue&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;35&lt;/td&gt;&lt;td&gt;Magenta&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;36&lt;/td&gt;&lt;td&gt;Cyan&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;97&lt;/td&gt;&lt;td&gt;White&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;49&lt;/td&gt;&lt;td&gt;Default bg color&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;40&lt;/td&gt;&lt;td&gt;Black bg&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;41&lt;/td&gt;&lt;td&gt;Red bg&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;42&lt;/td&gt;&lt;td&gt;Green bg&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;43&lt;/td&gt;&lt;td&gt;Yellow bg&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;44&lt;/td&gt;&lt;td&gt;Blue bg&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;45&lt;/td&gt;&lt;td&gt;Magenta bg&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;46&lt;/td&gt;&lt;td&gt;Cyan bg&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;right&quot;&gt;107&lt;/td&gt;&lt;td&gt;White bg&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;For more information about additional formatting options checkout &lt;a href=&quot;https://misc.flogisoft.com/bash/tip_colors_and_formatting&quot;&gt;Bash tips: Colors and formatting&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Other ways to achieve similar formatting are &lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?tput+1&quot;&gt;tput&lt;/a&gt; and &lt;a href=&quot;http://www.manpagez.com/man/5/terminfo/&quot;&gt;terminfo&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;bonus-2-my-actual-ps1&quot;&gt;Bonus 2: my actual PS1!&lt;/h2&gt;
&lt;p&gt;I keep &lt;a href=&quot;https://github.com/lmammino/dotfiles/blob/master/.bash_profile&quot;&gt;my &lt;code&gt;.bash_profile&lt;/code&gt;&lt;/a&gt; public on GitHub (not because it’s cool, but because this way I can easily clone it into different machines).&lt;/p&gt;
&lt;p&gt;If you are curious you can see how my &lt;em&gt;bash-emojification&lt;/em&gt; is actually done or what else I put in my &lt;code&gt;PS1&lt;/code&gt; variable or even some aliases I use.&lt;/p&gt;
&lt;p&gt;Feel free to tell me what you think or ask questions about it in the comment box in this article.&lt;/p&gt;
&lt;h2 id=&quot;bonus-3-a-bash-prompt-generator&quot;&gt;Bonus 3: A bash prompt generator&lt;/h2&gt;
&lt;p&gt;Of course there had to be a service online to help you with this stuff! It turns out there are many!
If you want to build your fancy Bash prompt in a &lt;em&gt;drag-and-dropppy&lt;/em&gt; or &lt;em&gt;clicky-clicky&lt;/em&gt; way, checkout these links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://bashrcgenerator.com/&quot;&gt;.bashrc PS1 generator by Julien Ricard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://ezprompt.net/&quot;&gt;Easy Bash PS1 Generator by Josh Matthews&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At this point, you should know enough to be able to build your own PS1 generator website! Maybe that’s an idea for you next &lt;em&gt;hack-weekend&lt;/em&gt;!&lt;/p&gt;
&lt;h2 id=&quot;bonus-4-use-the-return-code&quot;&gt;Bonus 4: Use the return code&lt;/h2&gt;
&lt;p&gt;This is an amazing snippet from &lt;a href=&quot;https://lobste.rs/u/bdesham&quot;&gt;@bdesham&lt;/a&gt; on &lt;em&gt;Lobste.rs&lt;/em&gt;.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;success_indicator&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [ &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;$?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; -eq &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; ] ; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;then&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;😎&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;else&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;💩&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;fi&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;PS1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;$(success_indicator) $ &apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;function success_indicator() {    if [ $? -eq 0 ] ; then        echo &amp;#x22;😎&amp;#x22;    else        echo &amp;#x22;💩&amp;#x22;    fi}export PS1=&amp;#x27;$(success_indicator) $ &amp;#x27;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;With this approach you won’t have a random emoji anymore but instead a very deterministic emoji given by the return code of the previous command. If the command exited successfully you will see a &lt;em&gt;cool dude&lt;/em&gt; emoji, otherwise a &lt;em&gt;surprised poop&lt;/em&gt; will show up on your prompt!&lt;/p&gt;
&lt;h2 id=&quot;why-all-of-this&quot;&gt;Why all of this?!&lt;/h2&gt;
&lt;p&gt;In the title of this article I said “how and why”, but if you have been careful you probably noticed I never really explained why you might want to go through all of this stuff!&lt;/p&gt;
&lt;p&gt;Well, the real reason why you should care about this is because “why not?!”&lt;/p&gt;
&lt;p&gt;Seriously, there isn’t a very strong reason why this stuff is important, it is definitely fun and interesting but you might be a fantastic developer even without having all this knowledge (and without emojis in your terminal)!&lt;/p&gt;
&lt;p&gt;Anyway, if this answer is not convincing you, I can actually prove that emojis in your terminal will make you more productive. Try to put a toilet (🚽) or a poop (💩) emoji in your list of supported emojis. Next time you’ll mistype a command and you’ll randomly see a poop emoji, I can assure you that you’ll have a bit of fun, your morale will stay up and you’ll hopefully keep pounding your way on the keyboard enjoying your work 😎.&lt;/p&gt;
&lt;p&gt;Whether you believe me or not on this, I hope I’ll see you soon in the next article 😜&lt;/p&gt;
&lt;p&gt;Byez!&lt;/p&gt;
&lt;p&gt;PS: A special thanks to all the people who contributed to this &lt;a href=&quot;https://lobste.rs/s/8oozfh/random_emoji_your_terminal_prompt_how_why&quot;&gt;Lobste.rs thread&lt;/a&gt;. A lot of great insights! Also, thanks to &lt;a href=&quot;https://www.reddit.com/user/gschizas&quot;&gt;@gschizas&lt;/a&gt; on Reddit for spotting some errors! 🙏&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/random-emoji-in-your-prompt-how-and-why.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/random-emoji-in-your-prompt-how-and-why.png" width="1200" height="630"/></media:content><category>bash</category><category>shell</category><author>Luciano Mammino</author><comments>https://loige.co/random-emoji-in-your-prompt-how-and-why/#comments</comments><enclosure url="https://loige.co/og/random-emoji-in-your-prompt-how-and-why.png" length="0" type="image/png"/></item><item><title>JavaScript iterator patterns</title><link>https://loige.co/javascript-iterator-patterns/</link><guid isPermaLink="true">https://loige.co/javascript-iterator-patterns/</guid><description>This article explores different ways to create iterators and iterable values in Javascript for dynamic sequence generation, specifically using functions, iterators, iterables and generators. It provides code examples for implementing the Fibonacci sequence with each approach.</description><pubDate>Mon, 21 Jan 2019 03:25:58 GMT</pubDate><content:encoded>&lt;p&gt;In this article we will explore different ways to create iterators and iterable
values in Javascript, specifically &lt;strong&gt;functions&lt;/strong&gt;, &lt;strong&gt;iterators&lt;/strong&gt;, &lt;strong&gt;iterables&lt;/strong&gt;
and &lt;strong&gt;generators&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;JavaScript is a very flexible language and most often you can achieve the same goals
in many different ways, iterators are no exception!&lt;/p&gt;
&lt;p&gt;Wikipedia defines iterators as follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In computer programming, an iterator is an object that enables a programmer
to traverse a container, particularly lists. Various types of iterators are
often provided via a container’s interface.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We will extend this definition even further as we will not focus on building
iterators for pre-computed values like lists, but we will see how to iterate over
generative sequences like the &lt;a href=&quot;https://en.wikipedia.org/wiki/Fibonacci_number&quot;&gt;Fibonacci sequence&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Most likely you won’t be using the Fibonacci sequence in your day to day programming
(unless you are interviewing for some company who wants to validate your knowledge
of recursion 😆), but the idea of generating a sequence of values on demand
(lazy evaluation) translates well to a lot of real-life scenarios like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;traversing custom data structures&lt;/li&gt;
&lt;li&gt;consuming paginated APIs&lt;/li&gt;
&lt;li&gt;draining a queue&lt;/li&gt;
&lt;li&gt;processing long files line by line&lt;/li&gt;
&lt;li&gt;read all the records from a SQL table&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-fibonacci-sequence&quot;&gt;The Fibonacci sequence&lt;/h2&gt;
&lt;p&gt;In case you have never seen the Fibonacci sequence before (or you don’t remember
the exact definition), here is how it looks like:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;1 1 2 3 5 8 13 21 ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;1 1 2 3 5 8 13 21 ...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Essentially, a number in the sequence is given by the sum of the previous 2 numbers.&lt;/p&gt;
&lt;p&gt;In more formal mathematical terms, you can define the sequence as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;F&lt;sub&gt;1&lt;/sub&gt; = F&lt;sub&gt;2&lt;/sub&gt; = 1&lt;br&gt;
F&lt;sub&gt;n&lt;/sub&gt; = F&lt;sub&gt;(n-1)&lt;/sub&gt; + F&lt;sub&gt;(n-2)&lt;/sub&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Few things to notice:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The sequence is infinite (it would be impossible to store it in a list without an upper limit).&lt;/li&gt;
&lt;li&gt;It is made by positive integers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, how do we write some JavaScript code that allows us to iterate over this sequence and
calculate an arbitrary number of elements?&lt;/p&gt;
&lt;p&gt;Well, there are many ways…&lt;/p&gt;
&lt;h2 id=&quot;functions&quot;&gt;Functions&lt;/h2&gt;
&lt;p&gt;In JavaScript, functions are first class citizens and most patterns can be modeled
with the use of only plain functions. This will become natural once you master
the concepts of &lt;em&gt;function scope&lt;/em&gt;, &lt;em&gt;anonymous functions&lt;/em&gt; and &lt;em&gt;nested functions&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So, how can we build a fibonacci sequence by using only functions?&lt;/p&gt;
&lt;p&gt;Here’s an example:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;genFib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Number&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.MAX_SAFE_INTEGER) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// initialize default values in the scope&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// returns an anonymous function that will return the next element&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// every time that it is called&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// calculates the next value&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;nextVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// redefines n1 and n2 to match new values&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;prevVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;n2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;n1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;prevVal&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// if we reached the upper bound return null (iteration completed)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// return the new value&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const genFib = (max = Number.MAX_SAFE_INTEGER) =&gt; {  // initialize default values in the scope  let n1 = 0  let n2 = 0  // returns an anonymous function that will return the next element  // every time that it is called  return () =&gt; {    // calculates the next value    const nextVal = n2 === 0 ? 1 : n1 + n2    // redefines n1 and n2 to match new values    const prevVal = n2    n2 = nextVal    n1 = prevVal    // if we reached the upper bound return null (iteration completed)    if (nextVal &gt;= max) {      return null    }    // return the new value    return nextVal  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;I added some comments to make the code easy to understand, but let’s go through it
once more.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;genFib&lt;/code&gt; is a function that accepts an optional parameter, which is the upper bound
used to define when to stop computing elements in the sequence. JavaScript numbers
starts to lose precision after &lt;code&gt;Number.MAX_SAFE_INTEGER&lt;/code&gt;, so this is a sensible default.&lt;/li&gt;
&lt;li&gt;The first thing that happens in the function is initializing the function scope.
&lt;code&gt;n1&lt;/code&gt; and &lt;code&gt;n2&lt;/code&gt; are the only two values that we need to compute an element of
the sequence. They represent the last 2 numbers computed. We set them to &lt;code&gt;0&lt;/code&gt; by default.&lt;/li&gt;
&lt;li&gt;At this point the function returns an anonymous function. This function can be
invoked an arbitrary number of times and every time it will compute and return
a new element in the sequence, making sure the internal state is updated accordingly.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Notice that &lt;code&gt;genFib&lt;/code&gt; will initizalize a new isolated scope containing &lt;code&gt;n1&lt;/code&gt; and &lt;code&gt;n2&lt;/code&gt;.
These values will be accessible (and modifiable) only by the anonymous function returned
by &lt;code&gt;genFib&lt;/code&gt;. This means that you can generate multiple “iterators” and everyone of them
will be independent from each other.&lt;/p&gt;
&lt;p&gt;To understand this even better let’s see an example on how a user would use this code:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;genFib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// limit the sequence to numbers below 6&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 5&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// null&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// null&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// null&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// or with a loop&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// prints all the numbers of the sequence below MAX_SAFE_INTEGER&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;f2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;genFib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;current&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; ((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;current&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;f2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!==&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;current&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const f = genFib(6) // limit the sequence to numbers below 6f() // 1f() // 1f() // 2f() // 3f() // 5f() // nullf() // nullf() // null// or with a loop// prints all the numbers of the sequence below MAX_SAFE_INTEGERconst f2 = genFib()let currentwhile ((current = f2()) !== null) {  console.log(current)}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;the-iterator-protocol&quot;&gt;The Iterator protocol&lt;/h2&gt;
&lt;p&gt;In the previous example we came up with our own way to define how to iterate through
the elements (returned anonymous function) and how to understand whether the sequence
was over (return of &lt;code&gt;null&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ECMAScript 2015&lt;/strong&gt; provides a standard and interoperable way to define iterator
objects. This is called &lt;strong&gt;the Iterator protocol&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In short, a JavaScript object is &lt;em&gt;an iterator&lt;/em&gt; if it implements a &lt;code&gt;next()&lt;/code&gt;
method with the following semantic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;next()&lt;/code&gt; does not accept any argument.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;next()&lt;/code&gt; has to return an object with 2 properties: &lt;code&gt;done&lt;/code&gt; and &lt;code&gt;value&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;done&lt;/code&gt; is a boolean and it will be set to &lt;code&gt;true&lt;/code&gt; if and only if there are no
more elements in the sequence.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;value&lt;/code&gt; will contain the actual value as computed in the last iteration
(could be &lt;code&gt;undefined&lt;/code&gt; when &lt;code&gt;done&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ok, now let’s rewrite our Fibonacci sequence to implement the Iterator protocol:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;genFibIterator&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Number&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.MAX_SAFE_INTEGER) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// this time we return an iterator object (rather than a function)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// the logic needed to compute the next element is inside the `next` method&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// calculates the next value&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// redefines n1 and n2 to match new values&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;prevVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;n2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;n1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;prevVal&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// if we reached the upper bound (iteration completed)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// set done to true and nextVal to undefined&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;done&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;false&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;nextVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;undefined&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;done&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// return the iteration object as for the iteration protocol&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;done&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const genFibIterator = (max = Number.MAX_SAFE_INTEGER) =&gt; {  let n1 = 0  let n2 = 0  // this time we return an iterator object (rather than a function)  return {    // the logic needed to compute the next element is inside the &amp;#x60;next&amp;#x60; method    next: () =&gt; {      // calculates the next value      let nextVal = n2 === 0 ? 1 : n1 + n2      // redefines n1 and n2 to match new values      const prevVal = n2      n2 = nextVal      n1 = prevVal      // if we reached the upper bound (iteration completed)      // set done to true and nextVal to undefined      let done = false      if (nextVal &gt;= max) {        nextVal = undefined        done = true      }      // return the iteration object as for the iteration protocol      return { value: nextVal, done }    }  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The comments in the code should help you to understand the new logic.&lt;/p&gt;
&lt;p&gt;Let’s see how to use our new Fibonacci iterator implementation:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;it&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;genFibIterator&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// { next: [Function: next] }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;it&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// { value: 1, done: false }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;it&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// { value: 1, done: false }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;it&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// { value: 2, done: false }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;it&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// { value: 3, done: false }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;it&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// { value: 5, done: false }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;it&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// { done: true }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// or&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;it2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;genFibIterator&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;it2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;done&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;it2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 5&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const it = genFibIterator(6) // { next: [Function: next] }it.next() // { value: 1, done: false }it.next() // { value: 1, done: false }it.next() // { value: 2, done: false }it.next() // { value: 3, done: false }it.next() // { value: 5, done: false }it.next() // { done: true }// orconst it2 = genFibIterator(6)let result = it2.next()while (!result.done) {  console.log(result.value)  result = it2.next()}// 1// 1// 2// 3// 5&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;the-iterable-protocol&quot;&gt;The Iterable protocol&lt;/h2&gt;
&lt;p&gt;In the previous section we saw how to define &lt;strong&gt;Iterator objects&lt;/strong&gt; that conform
the Iterator protocol. In reality, we might want to express the concept of
“iterability” in a more generic fashion, so that, given any object, we can tell if
such object is iterable or not.&lt;/p&gt;
&lt;p&gt;For this reason, ECMAScript 2015 defines also the &lt;strong&gt;Iterable protocol&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;An object is said to be &lt;em&gt;iterable&lt;/em&gt; if it exposes a property called &lt;code&gt;Symbol.iterator&lt;/code&gt;,
which is a function that returns an &lt;em&gt;iterator&lt;/em&gt; object.&lt;/p&gt;
&lt;p&gt;You can introspectively check if an object is &lt;em&gt;iterable&lt;/em&gt; with some code like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;isIterable&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;obj&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Boolean&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;obj&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#016C9A&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;obj&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Symbol&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#885D01&quot;&gt;iterator&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;function&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;function isIterable(obj) {  return Boolean(obj) &amp;#x26;&amp;#x26; typeof obj[Symbol.iterator] === &amp;#x27;function&amp;#x27;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;ECMAScript 2015 also provides a new &lt;code&gt;for&lt;/code&gt; construct (&lt;code&gt;for...of&lt;/code&gt;) that allows to
easily iterate over the elements of an iterable object:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;current&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;someIterable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;current&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;for (let current of someIterable) {  console.log(current)}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Iterable objects can also be used in combination with the &lt;strong&gt;spread operator&lt;/strong&gt; to
eagerly load all the values and store them into an array:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;allValues&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;someIterable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const allValues = [...someIterable]&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Ok, now let’s rewrite our Fibonacci sequence to implement the Iterable protocol:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;genFibIterable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Number&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.MAX_SAFE_INTEGER) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// returns an iterable object&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;Symbol&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#885D01&quot;&gt;iterator&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] () {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// returns an iterator&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;prevVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;n2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;n1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;prevVal&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;done&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;false&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;nextVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;undefined&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;done&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;done&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const genFibIterable = (max = Number.MAX_SAFE_INTEGER) =&gt; {  let n1 = 0  let n2 = 0  // returns an iterable object  return {    [Symbol.iterator] () {      // returns an iterator      return {        next() {          let nextVal = n2 === 0 ? 1 : n1 + n2          const prevVal = n2          n2 = nextVal          n1 = prevVal          let done = false          if (nextVal &gt;= max) {            nextVal = undefined            done = true          }          return { value: nextVal, done }        }      }    }  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;What we did here is to just move the implementation of the iterator seen in the
previous section into the &lt;code&gt;Symbol.iterator&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Note that it is possible to come up with an implementation that can satisfy the Iterator and the Iterable protocols
at the same time :&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;genFib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Number&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.MAX_SAFE_INTEGER) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// this satisfies the Iterator protocol&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;prevVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;n2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;n1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;prevVal&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;done&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;false&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;nextVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;undefined&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;done&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;done&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// this satisfies the Iterable protocol&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;Symbol&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#885D01&quot;&gt;iterator&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] () {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// returns `this` because the object itself is an iterator&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const genFib = (max = Number.MAX_SAFE_INTEGER) =&gt; {  let n1 = 0  let n2 = 0  return {    // this satisfies the Iterator protocol    next: () =&gt; {      let nextVal = n2 === 0 ? 1 : n1 + n2      const prevVal = n2      n2 = nextVal      n1 = prevVal      let done = false      if (nextVal &gt;= max) {        nextVal = undefined        done = true      }      return { value: nextVal, done }    },    // this satisfies the Iterable protocol    [Symbol.iterator] () {      // returns &amp;#x60;this&amp;#x60; because the object itself is an iterator      return this    }  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The comments in the code should help you to understand the logic in these 2
implementations.&lt;/p&gt;
&lt;p&gt;With this new approaches you can generate numbers from the Fibonacci sequence as
follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// prints all the numbers in the sequence until MAX_SAFE_INTEGER&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;genFibIterable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// creates an array with all the Fibonacci numbers lower than 17&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;f2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;genFibIterable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;17&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;lowerThan17&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;f2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;] &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// [ 1, 1, 2, 3, 5, 8, 13 ]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// prints all the numbers in the sequence until MAX_SAFE_INTEGERconst f = genFibIterable()for (let n of f) {  console.log(n)}// creates an array with all the Fibonacci numbers lower than 17const f2 = genFibIterable(17)const lowerThan17 = [...f2] // [ 1, 1, 2, 3, 5, 8, 13 ]&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If at this point you are still struggling to see the logical difference between
an &lt;em&gt;iterator&lt;/em&gt; and an &lt;em&gt;iterable&lt;/em&gt; object you can see it this way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An &lt;em&gt;iterable&lt;/em&gt; is an object on which you can iterate over.&lt;/li&gt;
&lt;li&gt;An &lt;em&gt;iterator&lt;/em&gt; is a cursor object that allows you to iterate over an &lt;em&gt;iterable&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;generators&quot;&gt;Generators&lt;/h2&gt;
&lt;p&gt;Another great addition coming from ECMAScript 2015 to JavaScript are &lt;strong&gt;Generators&lt;/strong&gt;.
More specifically, ECMAScript 2015 defines &lt;strong&gt;Generator functions&lt;/strong&gt; and &lt;strong&gt;Generator objects&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A &lt;code&gt;function*&lt;/code&gt; declaration (function keyword followed by an asterisk) defines
a &lt;em&gt;Generator function&lt;/em&gt;, which returns a &lt;em&gt;Generator object&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Generators are functions which can be exited and later re-entered.
Their context (variable bindings) will be saved across re-entrances.&lt;/p&gt;
&lt;p&gt;To simplify this concept a bit, you can see generator functions as functions that
can “return” (or “&lt;em&gt;yield&lt;/em&gt;”) multiple times.&lt;/p&gt;
&lt;p&gt;Let’s explore the generator syntax with a simple example:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// generator function&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function*&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;countTo3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;yield&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;yield&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// generator functionfunction* countTo3() {  yield 1  yield 2  return 3}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In this example we are defining a &lt;code&gt;counter&lt;/code&gt; that generates numbers from 1 to 3.
We can use it as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// c is a generator object&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;countTo3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// { value: 1, done: false }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// { value: 2, done: false }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// { value: 3, done: true }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// { done: true }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// { done: true }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// c is a generator objectconst c = countTo3()c.next() // { value: 1, done: false }c.next() // { value: 2, done: false }c.next() // { value: 3, done: true }c.next() // { done: true }c.next() // { done: true }// ...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;So, the way a generator works is the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When you invoke a &lt;em&gt;generator function&lt;/em&gt;, a &lt;em&gt;generator object&lt;/em&gt; is returned.&lt;/li&gt;
&lt;li&gt;Generator objects have a &lt;code&gt;next()&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;When you invoke the &lt;code&gt;next()&lt;/code&gt; method of a &lt;em&gt;generator object&lt;/em&gt; the code of the
generator will be executed until the first &lt;code&gt;yield&lt;/code&gt; (or &lt;code&gt;return&lt;/code&gt;) is encountered.&lt;/li&gt;
&lt;li&gt;If a &lt;code&gt;yield&lt;/code&gt; was found, the code is stopped and the yielded value will be passed
to the invoking context though an object with the following shape: &lt;code&gt;{ value: &amp;#x3C;yieldedValue&gt;, done: false }&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The next time &lt;code&gt;next()&lt;/code&gt; is invoked, the execution will be resumed from the point
where it was initially suspended until a new &lt;code&gt;yield&lt;/code&gt; or &lt;code&gt;return&lt;/code&gt; is found.&lt;/li&gt;
&lt;li&gt;If a &lt;code&gt;return&lt;/code&gt; statement is found (or the function completes), the object
returned will look like: &lt;code&gt;{ value: &amp;#x3C;returnedValue&gt;, done: true }&lt;/code&gt;
(notice the &lt;code&gt;done&lt;/code&gt; now set to &lt;code&gt;true&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Once the generator has completed, consecutive calls to &lt;code&gt;next()&lt;/code&gt; will always produce &lt;code&gt;{ done: true }&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, the reason why we are exploring this topic is because we can implement
our Fibonacci sequence as a generator:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function*&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Fib&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Number&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.MAX_SAFE_INTEGER) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// initialize the state variables&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// we can now pre-initialize nextVal to 1 as part of the state&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// loop until we exceed the max number&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;&amp;#x3C;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// yields the current value&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;yield&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// shifts nextVal -&gt; n2 and n2 -&gt; n1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;prevVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;n2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;nextVal&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;n1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;prevVal&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// calculates the next value&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;nextVal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;n2&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;function* Fib (max = Number.MAX_SAFE_INTEGER) {  // initialize the state variables  let n1 = 0  let n2 = 0  // we can now pre-initialize nextVal to 1 as part of the state  let nextVal = 1  // loop until we exceed the max number  while (nextVal &lt;= max) {    // yields the current value    yield nextVal    // shifts nextVal -&gt; n2 and n2 -&gt; n1    const prevVal = n2    n2 = nextVal    n1 = prevVal    // calculates the next value    nextVal = n1 + n2  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The comments in the code should help you with understanding this implementation.&lt;/p&gt;
&lt;p&gt;You can immediately notice that since we don’t have to deal with a &lt;em&gt;nested function&lt;/em&gt;,
the implementation seems easier to read, or at least it might feel easier to read
the code and understand the actual execution flow.&lt;/p&gt;
&lt;p&gt;For this reason, you might prefer to use generators over plain functions in this
kind of scenarios.&lt;/p&gt;
&lt;p&gt;We can use our new generator-based Fibonacci sequence as in this example:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;fib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Fib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;fib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// { value: 1, done: false }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;fib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// { value: 1, done: false }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;fib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// { value: 2, done: false }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;fib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// { value: 3, done: false }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;fib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// { value: 5, done: false }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;fib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// { done: true }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// or&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;fib2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Fib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;fib2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;done&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;fib2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 5&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const fib = Fib(6)fib.next() // { value: 1, done: false }fib.next() // { value: 1, done: false }fib.next() // { value: 2, done: false }fib.next() // { value: 3, done: false }fib.next() // { value: 5, done: false }fib.next() // { done: true }// orconst fib2 = Fib(6)let result = fib2.next()while (!result.done) {  console.log(result.value)  result = fib2.next()}// 1// 1// 2// 3// 5&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;At this point you might be wandering:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Is a generator object an iterator or an iterable?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Well, it turns out that &lt;strong&gt;a generator object is both an iterator and iterable&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;So you can also use our latest implementation with the &lt;code&gt;for...of&lt;/code&gt; and the &lt;em&gt;spread&lt;/em&gt;
syntax:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;fib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Fib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;current&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;fib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;current&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 5&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// or&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;fib2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Fib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;fib2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;] &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// [ 1 1 2 3 5 ]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const fib = Fib(6)for (let current of fib) {  console.log(current)}// 1// 1// 2// 3// 5// orconst fib2 = Fib(6)[...fib2] // [ 1 1 2 3 5 ]&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Finally, since generators are &lt;em&gt;iterators&lt;/em&gt;, you can use them as &lt;code&gt;Symbol.iterator&lt;/code&gt;
property of an &lt;em&gt;iterable object&lt;/em&gt;. This could help you to define the iteration logic
in a more elegant and concise way, taking advantage of the &lt;code&gt;yield&lt;/code&gt; keyword.&lt;/p&gt;
&lt;p&gt;To some extent, you can see generators as a syntactic sugar to define iterable objects.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article we learned about different ways to generate dynamic sequences using
plain functions, iterators, iterables and generators.&lt;/p&gt;
&lt;p&gt;Notice that these approaches are ideal when the operation needed to generate the
next element is synchronous (it doesn’t require external resources to be
loaded asynchronously).&lt;/p&gt;
&lt;p&gt;When you have to iterate over values that become available asynchronously you
have to rely on different patterns such as
&lt;a href=&quot;https://nodejs.org/api/events.html&quot;&gt;&lt;strong&gt;event emitters&lt;/strong&gt;&lt;/a&gt;,
&lt;a href=&quot;https://nodejs.org/api/stream.html&quot;&gt;&lt;strong&gt;streams&lt;/strong&gt;&lt;/a&gt;, or
&lt;a href=&quot;https://github.com/tc39/proposal-async-iteration&quot;&gt;&lt;strong&gt;async iterators&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also, notice that generators have some interesting advanced features not covered
in this article, like the opportunity to pass new values in the context every
time &lt;code&gt;.next()&lt;/code&gt; is called or to throw exceptions, so make sure you checkout
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator&quot;&gt;the generators documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you liked this article and you are interested in similar content, be sure
to checkout my book &lt;strong&gt;&lt;a href=&quot;https://www.nodejsdesignpatterns.com&quot;&gt;Node.js Design Patterns&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nodejsdesignpatterns.com&quot;&gt;&lt;img alt=&quot;Node.js Design Patterns Second Edition by Mario Casciaro and Luciano Mammino&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;200&quot; height=&quot;246&quot; src=&quot;https://loige.co/_astro/node-js-design-patterns.DVwehICB_2vjD0B.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This book contains more than 500 pages, filled with more than 100 examples on
Node.js (and JavaScript) design patterns. I am sure you won’t be disappointed!&lt;/p&gt;
&lt;p&gt;Have fun! :)&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/javascript-iterator-patterns.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/javascript-iterator-patterns.png" width="1200" height="630"/></media:content><category>javascript</category><category>node-js</category><category>design-patterns</category><author>Luciano Mammino</author><comments>https://loige.co/javascript-iterator-patterns/#comments</comments><enclosure url="https://loige.co/og/javascript-iterator-patterns.png" length="0" type="image/png"/></item><item><title>Create resources conditionally with CDK</title><link>https://loige.co/create-resources-conditionally-with-cdk/</link><guid isPermaLink="true">https://loige.co/create-resources-conditionally-with-cdk/</guid><description>This post explains how to conditionally create resources in AWS CDK using CfnCondition. It provides a practical example of creating an S3 bucket based on an SSM parameter value. The post covers defining a condition, attaching it to a low-level CDK construct, and importing the conditionally created resource.</description><pubDate>Mon, 01 Nov 2021 09:15:00 GMT</pubDate><content:encoded>&lt;p&gt;Did you ever need to create a resource based on a condition in CDK? I recently needed to do that and finding a viable solution for this problem took me longer than I originally anticipated. In this article I will try to summarise what I learned and present my solution.&lt;/p&gt;
&lt;p&gt;In short, we will learn about the &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.CfnCondition.html&quot;&gt;&lt;code&gt;CfnCondition&lt;/code&gt; construct&lt;/a&gt; and how it can be used to create CloudFormation conditions. Then we will see how to attach condition to low level construct. Throughout this article, we will discuss these concepts with a practical example: creating or importing an S3 bucket based on the value of an SSM parameter.&lt;/p&gt;
&lt;h2 id=&quot;create-or-import-an-s3-bucket-based-on-a-condition-with-cdk&quot;&gt;Create or import an S3 bucket based on a condition with CDK&lt;/h2&gt;
&lt;p&gt;Let’s start with a practical example: we want to define a stack using CDK and we need to be able to import or create an S3 bucket depending on a specific condition. Let’s also make a use case: our stack will be deployed to multiple environments (development, staging, production, etc.). In the production environment we will need to use a bucket that is already created, while in the other environments we want to create the bucket as part of the stack.&lt;/p&gt;
&lt;p&gt;If our condition can be expressed statically (e.g. using an environment variable or a value in the CDK context) then things are easy and we should be able to do something like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/core&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/aws-s3&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;ExampleStack&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Stack&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;constructor&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;scope&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Construct&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;props&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;StackProps&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;super&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;scope&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;myBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;CREATE_BUCKET&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;true&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Bucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;MyBucket&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Bucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fromBucketAttributes&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;MyBucket&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;bucketName&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;theNameOfTheBucketToImport&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import * as cdk from &amp;#x27;@aws-cdk/core&amp;#x27;import * as s3 from &amp;#x27;@aws-cdk/aws-s3&amp;#x27;export class ExampleStack extends cdk.Stack {  constructor (scope: cdk.Construct, id: string, props: cdk.StackProps) {    super(scope, id, props)    const myBucket = process.env[&amp;#x27;CREATE_BUCKET&amp;#x27;] === &amp;#x27;true&amp;#x27;      ? new s3.Bucket(this, &amp;#x27;MyBucket&amp;#x27;)      : s3.Bucket.fromBucketAttributes(this, &amp;#x27;MyBucket&amp;#x27;, {          bucketName: &amp;#x27;theNameOfTheBucketToImport&amp;#x27;        })  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;But what if we try to replace our expression (&lt;code&gt;process.env[&apos;CREATE_BUCKET&apos;] === &apos;true&apos;&lt;/code&gt;) with something that depends on other resources on our AWS account? For example, what if we use the value from an SSM parameter?&lt;/p&gt;
&lt;p&gt;Let’s see how that might look like:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ⚠️ NOTE: This does not work!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/core&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/aws-s3&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ssm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/aws-ssm&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;ExampleStack&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Stack&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;constructor&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;scope&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Construct&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;props&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;StackProps&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;super&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;scope&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;shouldCreateBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ssm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;StringParameter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fromStringParameterAttributes&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ShouldCreateBucket&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;parameterName&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`/ExampleStack/Config/ShouldCreateBucket`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;stringValue&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;myBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;shouldCreateBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;true&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Bucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;MyBucket&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Bucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fromBucketAttributes&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;MyBucket&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;bucketName&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;theNameOfTheBucketToImport&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// ⚠️ NOTE: This does not work!import * as cdk from &amp;#x27;@aws-cdk/core&amp;#x27;import * as s3 from &amp;#x27;@aws-cdk/aws-s3&amp;#x27;import * as ssm from &amp;#x27;@aws-cdk/aws-ssm&amp;#x27;export class ExampleStack extends cdk.Stack {  constructor (scope: cdk.Construct, id: string, props: cdk.StackProps) {    super(scope, id, props)    const shouldCreateBucket = ssm.StringParameter.fromStringParameterAttributes(      this,      &amp;#x27;ShouldCreateBucket&amp;#x27;,      {        parameterName: &amp;#x60;/ExampleStack/Config/ShouldCreateBucket&amp;#x60;      }    ).stringValue    const myBucket = shouldCreateBucket === &amp;#x27;true&amp;#x27;      ? new s3.Bucket(this, &amp;#x27;MyBucket&amp;#x27;)      : s3.Bucket.fromBucketAttributes(this, &amp;#x27;MyBucket&amp;#x27;, {          bucketName: &amp;#x27;theNameOfTheBucketToImport&amp;#x27;        })  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If you read the comment at the top of the snippet, you know already this does not work as expected. But what is actually happening here?&lt;/p&gt;
&lt;p&gt;Dynamic values like SSM Parameters are not known during the &lt;a href=&quot;https://docs.aws.amazon.com/cdk/latest/guide/apps.html#lifecycle&quot;&gt;&lt;em&gt;construct&lt;/em&gt; phase&lt;/a&gt;, which is the lifecycle phase in which our TypeScript code gets executed and CDK collects all the resources that we want to include in the stack. In this phase, CDK will use a &lt;a href=&quot;https://docs.aws.amazon.com/cdk/latest/guide/tokens.html&quot;&gt;&lt;em&gt;Token&lt;/em&gt;&lt;/a&gt; to represent these values in the context of TypeScript.&lt;/p&gt;
&lt;p&gt;So, in the example above, &lt;code&gt;shouldCreateBucket&lt;/code&gt; will not contain the actual string value that is stored in the SSM parameter &lt;code&gt;/ExampleStack/Config/ShouldCreateBucket&lt;/code&gt;. It will still be a sting value but it will contain something that will look like &lt;code&gt;${Token[TOKEN.55]}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Because of this, our TypeScript expression is effectively the following:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;${Token[TOKEN.55]}&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;true&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&amp;#x27;${Token[TOKEN.55]}&amp;#x27; === &amp;#x27;true&amp;#x27;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Which means that this expression will always evaluate to &lt;code&gt;false&lt;/code&gt;. Therefore, we are always importing the bucket and never creating it, regardless of the actual value in our SSM parameter.&lt;/p&gt;
&lt;p&gt;Of course, this is not what we want. But, how do we fix it?&lt;/p&gt;
&lt;h2 id=&quot;using-cfncondition-with-cdk&quot;&gt;Using &lt;code&gt;CfnCondition&lt;/code&gt; with CDK&lt;/h2&gt;
&lt;p&gt;The way to solve this problem is to use the concept of &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html&quot;&gt;&lt;em&gt;condition&lt;/em&gt; in CloudFormation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Conditions exists in CloudFormation to support use cases like ours. They allow to define the circumstances under which certain entities are created or configured for a given stack.&lt;/p&gt;
&lt;p&gt;Since we are working with CDK, we can use the concept of condition with the low level &lt;code&gt;CfnCondition&lt;/code&gt; construct.&lt;/p&gt;
&lt;p&gt;Let’s see how we can create a condition based on the SSM parameter from the previous example:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/core&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/aws-s3&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ssm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/aws-ssm&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;ExampleStack&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Stack&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;constructor&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;scope&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Construct&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;props&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;StackProps&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;super&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;scope&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;shouldCreateBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ssm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;StringParameter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fromStringParameterAttributes&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ShouldCreateBucket&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;parameterName&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`/ExampleStack/Config/ShouldCreateBucket`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;stringValue&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// here&apos;s the condition&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;shouldCreateBucketCondition&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;CfnCondition&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ShouldCreateBucketCondition&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// a condition needs an expression&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;expression&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;conditionEquals&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;shouldCreateBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;true&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import * as cdk from &amp;#x27;@aws-cdk/core&amp;#x27;import * as s3 from &amp;#x27;@aws-cdk/aws-s3&amp;#x27;import * as ssm from &amp;#x27;@aws-cdk/aws-ssm&amp;#x27;export class ExampleStack extends cdk.Stack {  constructor (scope: cdk.Construct, id: string, props: cdk.StackProps) {    super(scope, id, props)    const shouldCreateBucket = ssm.StringParameter.fromStringParameterAttributes(      this,      &amp;#x27;ShouldCreateBucket&amp;#x27;,      {        parameterName: &amp;#x60;/ExampleStack/Config/ShouldCreateBucket&amp;#x60;      }    ).stringValue    // here&amp;#x27;s the condition    const shouldCreateBucketCondition = new cdk.CfnCondition(      this,      &amp;#x27;ShouldCreateBucketCondition&amp;#x27;,      {        // a condition needs an expression        expression: cdk.Fn.conditionEquals(shouldCreateBucket, &amp;#x27;true&amp;#x27;)      }    )    // ...  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;As you can see, a condition is created as any other resource by instantiating an object from the &lt;code&gt;cdk.CfnCondition&lt;/code&gt; construct. Note that this is more of a logical resource as it does not create an actual resource on AWS. The interesting part is the &lt;code&gt;expression&lt;/code&gt; attribute.&lt;/p&gt;
&lt;p&gt;This attribute is used to define an expression that gets evaluated to determine the value of the condition which, at deployment time, needs to be either &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here we are using &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.Fn.html#static-conditionwbrequalslhs-rhs&quot;&gt;&lt;code&gt;cdk.Fn.conditionEquals&lt;/code&gt;&lt;/a&gt; to indicate that the condition will be &lt;code&gt;true&lt;/code&gt; if &lt;code&gt;shouldCreateBucket&lt;/code&gt; matches the string &lt;code&gt;&apos;true&apos;&lt;/code&gt;. There are other functions you can use to create more complicated conditions including thing like &lt;em&gt;and&lt;/em&gt; or &lt;em&gt;or&lt;/em&gt; operators. Check out the &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.Fn.html#class-fn&quot;&gt;documentation of the &lt;code&gt;Fn&lt;/code&gt; class&lt;/a&gt; if you want to find out more.&lt;/p&gt;
&lt;p&gt;This allow us to evaluate the expression at deployment time when the actual value of the SSM parameter will be available, therefore this condition will work as intended.&lt;/p&gt;
&lt;p&gt;Now, this condition alone doesn’t really do much. We need to &lt;em&gt;attach&lt;/em&gt; the condition to a resource to tell CDK (and CloudFormation) to actually create the given resource only if the condition holds true.&lt;/p&gt;
&lt;h2 id=&quot;attaching-a-condition-to-a-cdk-resource&quot;&gt;Attaching a condition to a CDK resource&lt;/h2&gt;
&lt;p&gt;This is where things get a little bit hairy and where I needed to spend a little bit of time to find a working solution.&lt;/p&gt;
&lt;p&gt;I was expecting to be able to do something like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ⚠️ NOTE: This does not work!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;myBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Bucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;MyBucket&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;shouldCreateBucketCondition&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// NOPE!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// or&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;myBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;setCondition&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;shouldCreateBucketCondition&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// NOPE!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// ⚠️ NOTE: This does not work!// ...const myBucket = new s3.Bucket(this, &amp;#x27;MyBucket&amp;#x27;, {  condition: shouldCreateBucketCondition // NOPE!})// ormyBucket.setCondition(shouldCreateBucketCondition) // NOPE!// ...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Eventually I figured out that I can’t specify a condition on a high level construct such as &lt;code&gt;s3.Bucket&lt;/code&gt; and that I need to &lt;a href=&quot;https://docs.aws.amazon.com/cdk/latest/guide/cfn_layer.html#cfn_layer_cfn&quot;&gt;fallback to the equivalent level 0 construct&lt;/a&gt; (&lt;code&gt;s3.CfnBucket&lt;/code&gt; in this case).&lt;/p&gt;
&lt;p&gt;Doing this is not really obvious and the final &lt;em&gt;downcast&lt;/em&gt; looks like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;cfnMyBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;myBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;defaultChild&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;CfnBucket&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const cfnMyBucket = myBucket.node.defaultChild as s3.CfnBucket&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Once we have an instance of &lt;code&gt;s3.CfnBucket&lt;/code&gt;, we can specify a condition with:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;cfnMyBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;cfnOptions&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;someCfnCondition&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;cfnMyBucket.cfnOptions.condition = someCfnCondition&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;So if we put what we have learned together, this is how our conditional creation of a bucket might look like:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/core&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/aws-s3&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ssm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/aws-ssm&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;ExampleStack&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Stack&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;constructor&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;scope&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Construct&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;props&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;StackProps&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;super&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;scope&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;shouldCreateBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ssm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;StringParameter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fromStringParameterAttributes&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ShouldCreateBucket&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;parameterName&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`/ExampleStack/Config/ShouldCreateBucket`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;stringValue&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;shouldCreateBucketCondition&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;CfnCondition&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ShouldCreateBucketCondition&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;expression&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;conditionEquals&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;shouldCreateBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;true&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;myBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Bucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;MyBucket&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;bucketName&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;my-special-bucket&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;myBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;defaultChild&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;CfnBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;cfnOptions&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;shouldCreateBucketCondition&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import * as cdk from &amp;#x27;@aws-cdk/core&amp;#x27;import * as s3 from &amp;#x27;@aws-cdk/aws-s3&amp;#x27;import * as ssm from &amp;#x27;@aws-cdk/aws-ssm&amp;#x27;export class ExampleStack extends cdk.Stack {  constructor (scope: cdk.Construct, id: string, props: cdk.StackProps) {    super(scope, id, props)    const shouldCreateBucket = ssm.StringParameter.fromStringParameterAttributes(      this,      &amp;#x27;ShouldCreateBucket&amp;#x27;,      {        parameterName: &amp;#x60;/ExampleStack/Config/ShouldCreateBucket&amp;#x60;      }    ).stringValue    const shouldCreateBucketCondition = new cdk.CfnCondition(      this,      &amp;#x27;ShouldCreateBucketCondition&amp;#x27;,      {        expression: cdk.Fn.conditionEquals(shouldCreateBucket, &amp;#x27;true&amp;#x27;)      }    )    const myBucket = new s3.Bucket(this, &amp;#x27;MyBucket&amp;#x27;, {      bucketName: &amp;#x27;my-special-bucket&amp;#x27;    })    (myBucket.node.defaultChild as s3.CfnBucket).cfnOptions.condition = shouldCreateBucketCondition  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The final point to address is to figure out how to import the bucket if our condition does not hold.&lt;/p&gt;
&lt;p&gt;After thinking about this for a while, I realised that we can always import the bucket. Based in our condition, one of two things can happen:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The bucket will be created (if the SSM parameter value is &lt;code&gt;true&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The bucket is already there (otherwise)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In both cases, if we know the unique name of the bucket, we can import it using &lt;code&gt;s3.Bucket.fromBucketAttributes&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;importedOrCreatedBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Bucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fromBucketAttributes&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ImportedOrCreatedBucket&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;bucketName&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;my-special-bucket&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const importedOrCreatedBucket = s3.Bucket.fromBucketAttributes(this, &amp;#x27;ImportedOrCreatedBucket&amp;#x27;, {  bucketName: &amp;#x27;my-special-bucket&amp;#x27;})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The code above will give us a valid reference to the bucket in both cases. We can use this &lt;em&gt;generic&lt;/em&gt; reference in our stack every time we want to do something with the bucket, for instance grant a permission to another resource:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;importedOrCreatedBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;grantReadWrite&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;someEc2Instance&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;importedOrCreatedBucket.grantReadWrite(someEc2Instance)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In summary, creating a resource conditionally with CDK requires us to do the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;define a &lt;code&gt;cdk.CfnCondition&lt;/code&gt; with a given expression&lt;/li&gt;
&lt;li&gt;downcast the resource we want to create conditionally to it’s level 0 construct equivalent (e.g. from &lt;code&gt;s3.Bucket&lt;/code&gt; to &lt;code&gt;s3.CfnBucket&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;attach the condition to the lower level construct using &lt;code&gt;cfnResource.cfnOptions.condition = myCondition&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;finally, if we need to reference this resource in the rest of our stack, we can import the resource using some attribute that will be know regardless if we just created the resource or if we are importing it (e.g. &lt;code&gt;s3.Bucket.fromBucketAttributes&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Our final snippet will look like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/core&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/aws-s3&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ssm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/aws-ssm&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;ExampleStack&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Stack&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;constructor&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;scope&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Construct&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;props&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;StackProps&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;super&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;scope&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// read the SSM parameter&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;shouldCreateBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ssm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;StringParameter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fromStringParameterAttributes&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ShouldCreateBucket&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;parameterName&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`/ExampleStack/Config/ShouldCreateBucket`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;stringValue&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// define the condition comparing the value of the SSM parmater to &apos;true&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;shouldCreateBucketCondition&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;CfnCondition&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ShouldCreateBucketCondition&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;expression&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;conditionEquals&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;shouldCreateBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;true&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// creates the bucket&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;myBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Bucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;MyBucket&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;bucketName&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;my-special-bucket&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// attaches a condition to the creation of the bucket&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;myBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;defaultChild&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;CfnBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;cfnOptions&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;condition&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;shouldCreateBucketCondition&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// import the bucket by name (regardless if it was just created or already existed)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;importedOrCreatedBucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;s3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Bucket&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fromBucketAttributes&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ImportedOrCreatedBucket&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;bucketName&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;my-special-bucket&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// from now on only use `importedOrCreatedBucket`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import * as cdk from &amp;#x27;@aws-cdk/core&amp;#x27;import * as s3 from &amp;#x27;@aws-cdk/aws-s3&amp;#x27;import * as ssm from &amp;#x27;@aws-cdk/aws-ssm&amp;#x27;export class ExampleStack extends cdk.Stack {  constructor (scope: cdk.Construct, id: string, props: cdk.StackProps) {    super(scope, id, props)    // read the SSM parameter    const shouldCreateBucket = ssm.StringParameter.fromStringParameterAttributes(      this,      &amp;#x27;ShouldCreateBucket&amp;#x27;,      {        parameterName: &amp;#x60;/ExampleStack/Config/ShouldCreateBucket&amp;#x60;      }    ).stringValue    // define the condition comparing the value of the SSM parmater to &amp;#x27;true&amp;#x27;    const shouldCreateBucketCondition = new cdk.CfnCondition(      this,      &amp;#x27;ShouldCreateBucketCondition&amp;#x27;,      {        expression: cdk.Fn.conditionEquals(shouldCreateBucket, &amp;#x27;true&amp;#x27;)      }    )    // creates the bucket    const myBucket = new s3.Bucket(this, &amp;#x27;MyBucket&amp;#x27;, {      bucketName: &amp;#x27;my-special-bucket&amp;#x27;    })    // attaches a condition to the creation of the bucket    (myBucket.node.defaultChild as s3.CfnBucket).cfnOptions.condition = shouldCreateBucketCondition    // import the bucket by name (regardless if it was just created or already existed)    const importedOrCreatedBucket = s3.Bucket.fromBucketAttributes(this, &amp;#x27;ImportedOrCreatedBucket&amp;#x27;, {      bucketName: &amp;#x27;my-special-bucket&amp;#x27;    })    // from now on only use &amp;#x60;importedOrCreatedBucket&amp;#x60;  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And this is all that I have to share for today!&lt;/p&gt;
&lt;p&gt;I hope you will find this useful and please let me know if you end up implementing something like this. I am still learning many of the CDK nuances, so I’d appreciate any feedback. Maybe there are other ways to achieve the same results.&lt;/p&gt;
&lt;p&gt;Make sure to leave a comment below and to &lt;a href=&quot;https://twitter.com/intent/user?screen_name=loige&quot;&gt;connect on Twitter&lt;/a&gt; so we can keep the conversation going.&lt;/p&gt;
&lt;p&gt;Until then, see you on the next post 👋&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/create-resources-conditionally-with-cdk.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/create-resources-conditionally-with-cdk.png" width="1200" height="630"/></media:content><category>aws</category><category>cdk</category><category>javascript</category><category>typescript</category><author>Luciano Mammino</author><comments>https://loige.co/create-resources-conditionally-with-cdk/#comments</comments><enclosure url="https://loige.co/og/create-resources-conditionally-with-cdk.png" length="0" type="image/png"/></item><item><title>Rust shenanigans: return type polymorphism</title><link>https://loige.co/rust-shenanigans-return-type-polymorphism/</link><guid isPermaLink="true">https://loige.co/rust-shenanigans-return-type-polymorphism/</guid><description>This article explores return type polymorphism in Rust through examples like Default::default() and a custom dice rolling library. The technique allows writing generic functions that can return different types based on usage. Useful for extensible APIs.</description><pubDate>Tue, 13 Apr 2021 09:15:00 GMT</pubDate><content:encoded>&lt;p&gt;In this article, I will describe Rust &lt;em&gt;return type polymorphism&lt;/em&gt; (a.k.a. &lt;em&gt;generic returns&lt;/em&gt;), a feature that I recently discovered and that I have been pretty intrigued about.&lt;/p&gt;
&lt;p&gt;I am seeing this feature for the first time in a programming language and at first glance, it did seem like some sort of built-in compiler magic, available only in the standard library. In reality, it is a generalised feature that you can use in your own code every day.&lt;/p&gt;
&lt;p&gt;Keep in mind that I am still quite a beginner with Rust, so my description might not be the most accurate but I will try to make a point on why I like this feature and how it works by using some examples. Hopefully, you will find this topic as interesting as I did!&lt;/p&gt;
&lt;p&gt;Ok, enough chit chat, let’s get into it! 🧐&lt;/p&gt;
&lt;h2 id=&quot;return-type-polymorphism-what&quot;&gt;Return type polymorphism, what?!&lt;/h2&gt;
&lt;p&gt;Before trying to explain what return type polymorphism actually is, let me show you a couple of interesting examples that might look familiar to you if you have been playing with Rust already:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;std&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;collections&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;HashSet&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;nums&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = [&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;17&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;22&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;48&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1997&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;22&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;nums_square_no_dups&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;HashSet&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;i32&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;nums&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;iter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(|&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;| &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; * &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;collect&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{:?}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;nums_square_no_dups&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// {2304, 484, 3988009, 4, 289}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;use std::collections::HashSet;fn main() {    let nums = [2, 17, 22, 48, 1997, 2, 22];    let nums_square_no_dups: HashSet&lt;i32&gt; = nums.iter().map(|x| x * x).collect();    println!(&amp;#x22;{:?}&amp;#x22;, nums_square_no_dups); // {2304, 484, 3988009, 4, 289}}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Ok, did you see it? I mean, how in the world is that &lt;code&gt;collect()&lt;/code&gt; figuring out that I want to “collect” values from an iterator into a &lt;code&gt;HashSet&lt;/code&gt; of integers? Indeed, it is giving me exactly a &lt;code&gt;HashSet&lt;/code&gt; of integers!&lt;/p&gt;
&lt;p&gt;Not convinced yet? We can also change this example slightly and see what happens… Let’s try with &lt;code&gt;Vec&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;nums&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = [&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;17&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;22&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;48&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1997&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;22&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;nums_square&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Vec&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;i32&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;nums&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;iter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(|&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;| &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; * &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;collect&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{:?}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;nums_square&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// [4, 289, 484, 2304, 3988009, 4, 484]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;fn main() {    let nums = [2, 17, 22, 48, 1997, 2, 22];    let nums_square: Vec&lt;i32&gt; = nums.iter().map(|x| x * x).collect();    println!(&amp;#x22;{:?}&amp;#x22;, nums_square); // [4, 289, 484, 2304, 3988009, 4, 484]}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Ok that’s not removing duplicates anymore and it’s preserving the order of elements, but that’s not the point! The point is that &lt;code&gt;collect()&lt;/code&gt; is still giving us what we want. This time we are asking for a &lt;code&gt;Vec&lt;/code&gt; and indeed we get a &lt;code&gt;Vec&lt;/code&gt; rather than a &lt;code&gt;HashMap&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Note that this code is almost the same as the previous one. We didn’t change anything other than the type declaration (and a variable name, but that’s irrelevant)!&lt;/p&gt;
&lt;p&gt;Also, keep in mind that, while Rust can ofter infer your types and, most often, you don’t have to provide explicit type definitions, when using &lt;code&gt;collect()&lt;/code&gt; the type definition is necessary.&lt;/p&gt;
&lt;p&gt;Let’s see what happens if we try to remove &lt;code&gt;Vec&amp;#x3C;i32&gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;nums&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = [&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;17&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;22&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;48&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1997&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;22&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;nums_square&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;nums&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;iter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(|&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;| &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; * &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;collect&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;fn main() {    let nums = [2, 17, 22, 48, 1997, 2, 22];    let nums_square = nums.iter().map(|x| x * x).collect();}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This example won’t to compile because collect doesn’t know what is the return type, so we get this nice-looking error:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;error[E0282]: type annotations needed&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;--&gt; src/main.rs:3:9&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|     let nums_square = nums.iter().map(|x| x * x).collect();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|         ^^^^^^^^^^^ consider giving `nums_square` a type&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;error[E0282]: type annotations needed --&gt; src/main.rs:3:9  |  |     let nums_square = nums.iter().map(|x| x * x).collect();  |         ^^^^^^^^^^^ consider giving &amp;#x60;nums_square&amp;#x60; a type&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;I hope you starting to get the point. Some functions like &lt;code&gt;collect()&lt;/code&gt; can &lt;em&gt;behave&lt;/em&gt; differently, based on the expected return type! The return type needs to be explicit, so the Rust compiler can pick the right behaviour for you.&lt;/p&gt;
&lt;p&gt;Ok, this is one of the first things I learned in Rust when doing coding challenges and I have been thinking for a while &lt;em&gt;“this is just some iterator magic and it probably works only for a few standard types”&lt;/em&gt;…&lt;/p&gt;
&lt;p&gt;Then, more recently I saw some other piece of code that was doing something like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; () {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;u8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;i64&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;d&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: (&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;u16&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;usize&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) = (&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;dbg!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// a = 0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;dbg!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// b = 0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;dbg!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// c = &quot;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;dbg!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;d&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// d = (0,0)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;fn main () {    let a: u8 = Default::default();    let b: i64 = Default::default();    let c: String = Default::default();    let d: (u16, usize) = (Default::default(), Default::default());    dbg!(a); // a = 0    dbg!(b); // b = 0    dbg!(c); // c = &amp;#x22;&amp;#x22;    dbg!(d); // d = (0,0)}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Ok, types have default values, so what?&lt;/p&gt;
&lt;p&gt;Yeah, nothing impressive, I know… But yet again, we are always calling the same function, this time &lt;code&gt;Default::default()&lt;/code&gt;, and it’s giving us the default value for the specific type we need!&lt;/p&gt;
&lt;p&gt;In all honesty, I am almost glanced over this one thinking it was some other nice Rust compile-time magic for built-in types. Until I noticed a small note saying &lt;em&gt;“by the way, you can have a default value for your custom types if you want to”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;That got my attention, and the example I saw was something like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;#[derive(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Debug&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Point3D&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;f64&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;f64&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;z&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;f64&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// it&apos;s easy pal, just implement the `Default` trait&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Point3D&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Point3D&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0_&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;f64&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0_&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;f64&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;z&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0_&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;f64&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;origin&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Point3D&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{:?}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;origin&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Point3D { x: 0.0, y: 0.0, z: 0.0 }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;#[derive(Debug)]struct Point3D {    x: f64,    y: f64,    z: f64,}// it&amp;#x27;s easy pal, just implement the &amp;#x60;Default&amp;#x60; traitimpl Default for Point3D {    fn default() -&gt; Self {        Point3D {            x: 0_f64,            y: 0_f64,            z: 0_f64,        }    }}fn main() {    let origin: Point3D = Default::default();    println!(&amp;#x22;{:?}&amp;#x22;, origin); // Point3D { x: 0.0, y: 0.0, z: 0.0 }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The &lt;a href=&quot;https://doc.rust-lang.org/std/default/trait.Default.html&quot;&gt;&lt;code&gt;Default&lt;/code&gt; trait&lt;/a&gt; allows you to define what’s the default value for your custom types. The trait forces you to implement a &lt;code&gt;default()&lt;/code&gt; method which must return an instance of the given type (&lt;code&gt;Self&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Again, nothing extremely exciting here… except that at this point something clicked in my head and I started to ask myself &lt;em&gt;“so this is some sort of generalised feature that everyone can use…”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;My suspicion was that the &lt;code&gt;Default::default()&lt;/code&gt; function can somehow infer the expected return type and, if that type implements the &lt;code&gt;Default&lt;/code&gt; trait, then it simply calls the &lt;code&gt;default()&lt;/code&gt; function for that type.&lt;/p&gt;
&lt;p&gt;Of course, I immediately went and looked for the actual &lt;a href=&quot;https://doc.rust-lang.org/1.51.0/src/core/default.rs.html#158&quot;&gt;implementation of &lt;code&gt;Default::default()&lt;/code&gt;&lt;/a&gt; to validate my guess.&lt;/p&gt;
&lt;p&gt;Now, I am not going to claim I understood the implementation 100% (there are some lovely macros in there and my brain can’t compile those just yet), but I had a feeling that I was on the right path with my guess.&lt;/p&gt;
&lt;p&gt;The interesting bit is the full signature of the &lt;code&gt;Default::default()&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt;() -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;pub fn default&lt;T: Default&gt;() -&gt; T {    // ...}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;I read this as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Default::default()&lt;/code&gt; has a generic parameter &lt;code&gt;T&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;T&lt;/code&gt; has a constraint: it can be any type as long as it implements the &lt;code&gt;Default&lt;/code&gt; trait&lt;/li&gt;
&lt;li&gt;finally (and this is the important point), &lt;code&gt;T&lt;/code&gt; is the type that &lt;code&gt;Default::default()&lt;/code&gt; must return&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And this is where the &lt;em&gt;magic&lt;/em&gt; is coming from. The implementation is actually generic over the return type. Also, by using the &lt;code&gt;Default&lt;/code&gt; trait constraint, we can have an extensible definition: anyone can implement new types that will work with &lt;code&gt;Default::default()&lt;/code&gt;. More on this later…&lt;/p&gt;
&lt;p&gt;For now, this is enough theory to digest, let’s try to do something with it!&lt;/p&gt;
&lt;h2 id=&quot;lets-build-something&quot;&gt;Let’s build something&lt;/h2&gt;
&lt;p&gt;Over the years, I learned that my brain can appreciate new programming concepts when I can build something using them. So, I rolled up my sleeves and started to think &lt;em&gt;“OK, what can I possibly build with this?”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I suppose, a good question here is &lt;em&gt;“When do I want to do different things based on different expected return type?”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I came up with a simple idea related to board games. Something like D&amp;#x26;D where you have different kind of dice (different number of faces).&lt;/p&gt;
&lt;p&gt;Can we use return type polymorphism to be able to &lt;em&gt;roll&lt;/em&gt; different type of dice?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A dice set from Dungeon and Dragons (D&amp;amp;#x26;D)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;604&quot; height=&quot;448&quot; src=&quot;https://loige.co/_astro/dungeon-and-dragong-dice-set-rust-return-type-polymorphism.Bq3i0v3W_Z8mkQz.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;I think we can! This is more or less what I did with my first attempt:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;rand&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::{thread_rng, &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Rng&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;trait&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;#[derive(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Debug&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;D6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;u8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;#[derive(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Debug&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;D8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;u8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Die&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Die&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;thread_rng&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;gen_range&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;..=&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Die&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;thread_rng&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;gen_range&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;..=&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// let&apos;s roll a D6&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Die&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{:?}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// D6(3)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// let&apos;s roll a D8&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Die&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{:?}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// D8(3)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;use rand::{thread_rng, Rng};trait Roll&lt;T&gt; {    fn roll() -&gt; T;}#[derive(Debug)]struct D6(u8);#[derive(Debug)]struct D8(u8);struct Die {}impl Roll&lt;D6&gt; for Die {    fn roll() -&gt; D6 {        D6 {            0: thread_rng().gen_range(1..=6),        }    }}impl Roll&lt;D8&gt; for Die {    fn roll() -&gt; D8 {        D8 {            0: thread_rng().gen_range(1..=8),        }    }}fn main() {    // let&amp;#x27;s roll a D6    let roll: D6 = Die::roll();    println!(&amp;#x22;{:?}&amp;#x22;, roll); // D6(3)    // let&amp;#x27;s roll a D8    let roll: D8 = Die::roll();    println!(&amp;#x22;{:?}&amp;#x22;, roll); // D8(3)}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;For simplicity, I am showing only how I implemented &lt;code&gt;D6&lt;/code&gt; and &lt;code&gt;D8&lt;/code&gt;. If you want the full version, check out my &lt;a href=&quot;https://play.rust-lang.org/?version=stable&amp;#x26;mode=debug&amp;#x26;edition=2018&amp;#x26;gist=4191ce04d3db0f102cd73a31e0864cb9&quot;&gt;D&amp;#x26;D dice Rust playground&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The interesting part of this implementation is that I have 2 different implementations for the function &lt;code&gt;Die::roll()&lt;/code&gt;, one returns a &lt;code&gt;D6&lt;/code&gt; (6-faces die) roll and the other returns a &lt;code&gt;D8&lt;/code&gt; (8-faces die) roll.&lt;/p&gt;
&lt;p&gt;Rust will automatically call the correct implementation based on what’s the expected return type for that invocation.&lt;/p&gt;
&lt;p&gt;Well done to me for using return type polymorphism!&lt;/p&gt;
&lt;h2 id=&quot;lets-make-it-extensible&quot;&gt;Let’s make it extensible&lt;/h2&gt;
&lt;p&gt;Ok, but my silly implementation has a problem: it is not extensible.&lt;/p&gt;
&lt;p&gt;I mean, what if I turn this code into a library and someone needs to implement a custom die with 100 faces? Or what if they want a trick die that always rolls 100?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A Dungeon and Dragons D100, a die with 100 faces&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;356&quot; height=&quot;350&quot; src=&quot;https://loige.co/_astro/dungeon-and-dragong-d100-rust-return-type-polymorphism.A3XLjIc4_lW8yM.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;How can we support this use case?&lt;/p&gt;
&lt;p&gt;Well, that’s pretty much what &lt;code&gt;Default::default()&lt;/code&gt; does, so it should be possible, right?&lt;/p&gt;
&lt;p&gt;Ok, here’s an idea:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We can define a public &lt;code&gt;Rollable&lt;/code&gt; trait that makes dice, well … &lt;em&gt;rollable&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Our standard &lt;code&gt;D6&lt;/code&gt; and &lt;code&gt;D8&lt;/code&gt; will implement the &lt;code&gt;Rollable&lt;/code&gt; trait to be rollable themselves&lt;/li&gt;
&lt;li&gt;We provide one single implementation for our &lt;code&gt;roll()&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;We make that one implementation generic over a &lt;code&gt;T&lt;/code&gt; where &lt;code&gt;T&lt;/code&gt; must implement &lt;code&gt;Rollable&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;T&lt;/code&gt; is also the return type for &lt;code&gt;roll()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Now, this implementation of &lt;code&gt;roll()&lt;/code&gt; just needs to use the &lt;code&gt;Rollable&lt;/code&gt; trait on the current type for &lt;code&gt;T&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This idea isn’t really original. We are pretty much mimicking what &lt;code&gt;Default::default()&lt;/code&gt; does with the trait &lt;code&gt;Default&lt;/code&gt;, except that their naming choice is maybe slightly more confusing, since the module, the function and the trait are all called &lt;em&gt;default&lt;/em&gt; 😰 …&lt;/p&gt;
&lt;p&gt;Let’s see how it looks like in code:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;rand&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::{thread_rng, &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Rng&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/// This is the trait that every die needs to implement to be... well... &quot;rollable&quot;, right?&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;trait&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Rollable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/// Roll the die&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/// Get the value from the latest roll&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;u8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/// A generic function to roll a given die.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Rollable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt;() -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Rollable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// &amp;#x3C;- Note that here `Rollable` is the current type for a given call!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/// A D6 die (6 faces): a roll will give you a `u8` in the `1..=6` range.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;#[derive(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Debug&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;D6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;u8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Rollable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;thread_rng&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;gen_range&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;..=&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;u8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;/// A D8 die (8 faces): a roll will give you a `u8` in the `1..=8` range.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;#[derive(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Debug&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;D8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;u8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Rollable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;thread_rng&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;gen_range&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;..=&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;u8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;use rand::{thread_rng, Rng};/// This is the trait that every die needs to implement to be... well... &amp;#x22;rollable&amp;#x22;, right?pub trait Rollable {    /// Roll the die    fn roll() -&gt; Self;    /// Get the value from the latest roll    fn val(&amp;#x26;self) -&gt; u8;}/// A generic function to roll a given die.pub fn roll&lt;T: Rollable&gt;() -&gt; T {    Rollable::roll() // &lt;- Note that here &amp;#x60;Rollable&amp;#x60; is the current type for a given call!}/// A D6 die (6 faces): a roll will give you a &amp;#x60;u8&amp;#x60; in the &amp;#x60;1..=6&amp;#x60; range.#[derive(Debug)]pub struct D6(u8);impl Rollable for D6 {    fn roll() -&gt; D6 {        D6 {            0: thread_rng().gen_range(1..=6),        }    }    fn val(&amp;#x26;self) -&gt; u8 {        self.0    }}/// A D8 die (8 faces): a roll will give you a &amp;#x60;u8&amp;#x60; in the &amp;#x60;1..=8&amp;#x60; range.#[derive(Debug)]pub struct D8(u8);impl Rollable for D8 {    fn roll() -&gt; D8 {        D8 {            0: thread_rng().gen_range(1..=8),        }    }    fn val(&amp;#x26;self) -&gt; u8 {        self.0    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That’s pretty much it, now we can keep using our &lt;code&gt;D6&lt;/code&gt; and &lt;code&gt;D8&lt;/code&gt; as before:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// let&apos;s roll a D6&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{:?}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// D6(3)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// let&apos;s roll a D8&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{:?}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// D8(3)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;fn main() {    // let&amp;#x27;s roll a D6    let r: D6 = roll();    println!(&amp;#x22;{:?}&amp;#x22;, r); // D6(3)    // let&amp;#x27;s roll a D8    let r: D8 = roll();    println!(&amp;#x22;{:?}&amp;#x22;, r); // D8(3)}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;But now, anyone using this library, can also implement their own custom dice:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;#[derive(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Debug&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Fake100&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;u8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Rollable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Fake100&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Fake100&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Fake100&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// &amp;#x3C;- forces it to roll 100&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;u8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;I bet I&apos;ll get a 100 this time!&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;d&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Fake100&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Look what I got: {}!&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;d&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// &amp;#x3C;- yeah this will always be 100&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;#[derive(Debug)]struct Fake100(u8);impl Rollable for Fake100 {    fn roll() -&gt; Fake100 {        Fake100 { 0: 100 } // &lt;- forces it to roll 100    }    fn val(&amp;#x26;self) -&gt; u8 {        self.0    }}fn main() {    println!(&amp;#x22;I bet I&amp;#x27;ll get a 100 this time!&amp;#x22;);    let d: Fake100 = roll();    println!(&amp;#x22;Look what I got: {}!&amp;#x22;, d.val()) // &lt;- yeah this will always be 100}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Pretty neat, isn’t it!?&lt;/p&gt;
&lt;p&gt;I actually did end up publishing this silly example &lt;a href=&quot;https://crates.io/crates/rollz&quot;&gt;as a library&lt;/a&gt;. Check it out. Who knows, maybe you do really want to implement a board game of some sort!&lt;/p&gt;
&lt;h2 id=&quot;the-turbo-fish-syntax&quot;&gt;The turbo-fish syntax&lt;/h2&gt;
&lt;p&gt;There is still one interesting detail to discuss before we can wrap this up.&lt;/p&gt;
&lt;p&gt;We already saw that, when a function is using return type polymorphism, we need to explicitly declare the expected type.&lt;/p&gt;
&lt;p&gt;What if you want to call a function implementing return type polymorphism but you don’t want to assign it? Let’s say we want to use the returned value immediately, maybe in a &lt;code&gt;println!()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{:?}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,  &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;fn main() {    println!(&amp;#x22;{:?}&amp;#x22;,  roll());}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;How can Rust understand what we want?&lt;/p&gt;
&lt;p&gt;In fact, it doesn’t! If you try to compile that code you will get a beautiful error message:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;error[E0282]: type annotations needed&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;--&gt; src/main.rs:47:23&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|     println!(&quot;{:?}&quot;,  roll());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|                       ^^^^ cannot infer type for type parameter `T` declared on the function `roll`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;error[E0282]: type annotations needed  --&gt; src/main.rs:47:23   |   |     println!(&amp;#x22;{:?}&amp;#x22;,  roll());   |                       ^^^^ cannot infer type for type parameter &amp;#x60;T&amp;#x60; declared on the function &amp;#x60;roll&amp;#x60;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The compiler also suggests running &lt;code&gt;rustc --explain E0282&lt;/code&gt; to get a detailed guide on how to solve this problem. You gotta give it to the Rust team, they have done such a tremendous job in terms of providing great documentation!&lt;/p&gt;
&lt;p&gt;Now, if you are patient enough to run that command and read the guide, you will find that we can solve this issue with the so-called &lt;strong&gt;turbo-fish&lt;/strong&gt; syntax!&lt;/p&gt;
&lt;p&gt;The turbo-fish syntax looks like… a fish: &lt;code&gt;::&amp;#x3C;&gt;&lt;/code&gt; … yeah, with some degree of imagination!&lt;/p&gt;
&lt;p&gt;So, this is how we actually use it to specify &lt;strong&gt;at call time&lt;/strong&gt; the type for the generic parameter:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{:?}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,  &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;fn main() {    println!(&amp;#x22;{:?}&amp;#x22;,  roll::&lt;D6&gt;());}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;OK… Maybe &lt;code&gt;::&amp;#x3C;D6&gt;()&lt;/code&gt; looks a bit more like a fish…&lt;/p&gt;
&lt;p&gt;Anyhow, with this syntax, the type for the parameter &lt;code&gt;T&lt;/code&gt; is not ambiguous anymore: we are explicitly saying we want a &lt;code&gt;D6&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;In reality, the turbo fish is the extended syntax for functions with generic types, except that, when we are doing an assignment with an well defined type, the Rust compiler is smart enough to infer the type of generic parameters and make our life easier.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2021-04-14:&lt;/strong&gt; Note though that Rust can infer types from function arguments, so in most cases you can still rely on type inference. Let’s see a quick example:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;try_dodge_attack&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;d6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;d8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;D8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;d6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() + &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;d8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() &gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;10&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;escaped&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;try_dodge_attack&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;roll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;match&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;escaped&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;You dogded!&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Ouch! The attack hit you!&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;fn try_dodge_attack(d6: D6, d8: D8) -&gt; bool {    d6.val() + d8.val() &gt; 10}fn main() {    let escaped = try_dodge_attack(roll(), roll());    println!(        &amp;#x22;{}&amp;#x22;,        match escaped {            true =&gt; &amp;#x22;You dogded!&amp;#x22;,            false =&gt; &amp;#x22;Ouch! The attack hit you!&amp;#x22;,        }    );}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In this example, we are calling &lt;code&gt;try_dodge_attack(roll(), roll())&lt;/code&gt; and we don’t have to use the turbo-fish syntax. The Rust compiler looks at the type declaration of the function arguments and figures out that we want to roll a &lt;code&gt;D6&lt;/code&gt; and a &lt;code&gt;D8&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This concludes our exploration of Rust return type polymorphism.&lt;/p&gt;
&lt;p&gt;I do hope you found this topic (and this article!) as interesting as I did and feel more than welcome to let me know in the comments if you did know about this capability already. Are you already using it in production somewhere? I’d be really curious to know your use case, so please share it with me 😇&lt;/p&gt;
&lt;p&gt;If you want a much more polished and detailed explanation of this idea check out this brilliant blog post by &lt;a href=&quot;https://twitter.com/jcoglan&quot;&gt;James Coglan&lt;/a&gt; called &lt;a href=&quot;https://blog.jcoglan.com/2019/04/22/generic-returns-in-rust/&quot;&gt;Generic returns in Rust&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That’s all from me now, see you in the next post! 👋&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Thanks to &lt;a href=&quot;https://twitter.com/AlleviTommaso&quot;&gt;@AlleviTommaso&lt;/a&gt; for reviewing this article!&lt;/small&gt;&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/rust-shenanigans-return-type-polymorphism.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/rust-shenanigans-return-type-polymorphism.png" width="1200" height="630"/></media:content><category>rust</category><author>Luciano Mammino</author><comments>https://loige.co/rust-shenanigans-return-type-polymorphism/#comments</comments><enclosure url="https://loige.co/og/rust-shenanigans-return-type-polymorphism.png" length="0" type="image/png"/></item><item><title>Emerging JavaScript pattern: multiple return values</title><link>https://loige.co/emerging-javascript-pattern-multiple-return-values/</link><guid isPermaLink="true">https://loige.co/emerging-javascript-pattern-multiple-return-values/</guid><description>This article explores how to simulate multiple return values in JavaScript using arrays and objects. It covers use cases like React Hooks and async/await error handling. The pattern enables elegant APIs but has performance implications.</description><pubDate>Sun, 11 Nov 2018 17:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this article, I want to explore an interesting pattern that I am seeing more and more in JavaScript code which allows you to return multiple values from a function.&lt;/p&gt;
&lt;p&gt;You probably know already that JavaScript does not support multiple return values natively, so this article will actually explore some ways to “simulate” this behavior.&lt;/p&gt;
&lt;p&gt;One of the most famous usages of this pattern I have seen recently is within &lt;a href=&quot;https://reactjs.org/docs/hooks-overview.html&quot;&gt;React Hooks&lt;/a&gt;, but before delving into that, let’s see what I mean with “multiple return values” by exploring this concept in other languages.&lt;/p&gt;
&lt;h2 id=&quot;multiple-return-values-in-other-languages&quot;&gt;Multiple return values in other languages&lt;/h2&gt;
&lt;p&gt;Two languages that come to my mind which natively support multiple return values are Lua and Go. Let’s implement a simple &lt;em&gt;integer division&lt;/em&gt; function that returns both the &lt;em&gt;quotient&lt;/em&gt; and the &lt;em&gt;remainder&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&quot;lua&quot;&gt;Lua&lt;/h3&gt;
&lt;p&gt;Let’s start with a simple implementation in Lua. It’s definitely worth mentioning that &lt;a href=&quot;https://www.lua.org/pil/5.1.html&quot;&gt;Lua’s official documentation&lt;/a&gt; defines multiple return values as &lt;em&gt;“An unconventional, but quite convenient feature”&lt;/em&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;lua&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;intDiv&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;divisor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;local&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;quotient&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;math.floor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; / &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;divisor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;local&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;remainder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; % &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;divisor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;quotient&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;remainder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;intDiv&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;-- 3  1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;function intDiv (dividend, divisor)  local quotient = math.floor(dividend / divisor)  local remainder = dividend % divisor  return quotient, remainderendprint(intDiv(10,3)) -- 3  1&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;go&quot;&gt;Go&lt;/h3&gt;
&lt;p&gt;Here’s some equivalent code in Go:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;package&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;main&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;fmt&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;intDiv&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;divisor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#A626A4&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) (&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#A626A4&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#A626A4&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;quotient&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; := &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; / &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;divisor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;remainder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; := &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; % &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;divisor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;quotient&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;remainder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Println&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;intDiv&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 3 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;package mainimport &amp;#x22;fmt&amp;#x22;func intDiv(dividend, divisor int) (int, int) {  quotient := dividend / divisor  remainder := dividend % divisor  return quotient, remainder}func main() {  fmt.Println(intDiv(10,3)) // 3 1}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;As you can see in these 2 code snippets, functions can return more than 1 value and this can be very convenient in cases where you logically have produce multiple outputs in a computation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: a more realistic implementation in Go, would take into account errors (e.g. division by 0) and add an extra return value to propagate potential errors. We shouldn’t worry too much about this for the sake of this article, but it is definitely worth mentioning that multiple return values in Go shine when it comes to error propagation and error handling. We will touch a bit more on this later in this article to see how this idea can be applied to JavaScript as well, especially in the context of Async/Await.&lt;/p&gt;
&lt;h2 id=&quot;simulating-multiple-return-values-in-javascript&quot;&gt;Simulating multiple return values in JavaScript&lt;/h2&gt;
&lt;p&gt;So, as we said early on, JavaScript does not natively support a syntax to return more than one value from a function. We can workaround this limitation by using &lt;em&gt;composite values&lt;/em&gt; like arrays or objects.&lt;/p&gt;
&lt;h3 id=&quot;multiple-return-values-with-arrays&quot;&gt;Multiple return values with arrays&lt;/h3&gt;
&lt;p&gt;Let’s implement our &lt;code&gt;intDiv&lt;/code&gt; in JavaScript by using arrays as return types:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;intDiv&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;divisor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;quotient&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Math&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;floor&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;divisor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;remainder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;divisor&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;quotient&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;remainder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;intDiv&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// [ 3, 1 ]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;intDiv = (dividend, divisor) =&gt; {  const quotient = Math.floor(dividend / divisor)  const remainder = dividend % divisor  return [quotient, remainder]}console.log(intDiv(10, 3)) // [ 3, 1 ]&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Here we are just printing the result of a division, but let’s assume we want to handle the two return values individually, how do we &lt;em&gt;reference&lt;/em&gt; those?&lt;/p&gt;
&lt;p&gt;Well, the return value is an array so we can simply access the two elements in the array using the indices &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;intDiv&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;quotient&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;remainder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`Quotient = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;quotient&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Quotient = 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`Remainder = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;remainder&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Remainder = 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const result = intDiv(10, 3)const quotient = result[0]const remainder = result[1]console.log(&amp;#x60;Quotient = ${quotient}&amp;#x60;) // Quotient = 3console.log(&amp;#x60;Remainder = ${remainder}&amp;#x60;) // Remainder = 1&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This syntax is arguably verbose and definitely not very elegant. Thankfully, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment&quot;&gt;ES2015 array destructuring assignment&lt;/a&gt; can help us here:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;quotient&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;remainder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;intDiv&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`Quotient = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;quotient&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Quotient = 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`Remainder = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;remainder&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Remainder = 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const [quotient, remainder] = intDiv(10, 3)console.log(&amp;#x60;Quotient = ${quotient}&amp;#x60;) // Quotient = 3console.log(&amp;#x60;Remainder = ${remainder}&amp;#x60;) // Remainder = 1&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This is much nicer to read and we also trimmed away 2 out 3 lines of code, big win!&lt;/p&gt;
&lt;p&gt;As nice as it is, this implementation has an important shortcoming: return values are positional, so you need to be careful and respect the order while destructuring.&lt;/p&gt;
&lt;h3 id=&quot;multiple-return-values-with-objects&quot;&gt;Multiple return values with objects&lt;/h3&gt;
&lt;p&gt;An alternative implementation could use objects as return value, let’s see how:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;intDiv&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;divisor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;quotient&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Math&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;floor&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;divisor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;remainder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;dividend&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;divisor&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;quotient&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;remainder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;intDiv = (dividend, divisor) =&gt; {  const quotient = Math.floor(dividend / divisor)  const remainder = dividend % divisor  return { quotient, remainder }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note that here we are using another syntactic sugar from ES2015 (Enhanced object literal syntax) that allows us to define objects very concisely. Prior to ES2015, we would have defined the return statement as &lt;code&gt;{quotient: quotient, remainder: remainder}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With this approach we will be able to use our &lt;code&gt;intDiv&lt;/code&gt; function as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;intDiv&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;quotient&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;quotient&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;remainder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;remainder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`Quotient = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;quotient&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Quotient = 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`Remainder = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;remainder&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Remainder = 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const result = intDiv(10, 3)const quotient = result.quotientconst remainder = result.remainderconsole.log(&amp;#x60;Quotient = ${quotient}&amp;#x60;) // Quotient = 3console.log(&amp;#x60;Remainder = ${remainder}&amp;#x60;) // Remainder = 1&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Again, this is a bit too verbose and ES2015 has another fantastic syntactic sugar to make this nicer:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;quotient&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;remainder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;intDiv&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`Quotient = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;quotient&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Quotient = 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`Remainder = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;remainder&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Remainder = 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const { quotient, remainder } = intDiv(10, 3)console.log(&amp;#x60;Quotient = ${quotient}&amp;#x60;) // Quotient = 3console.log(&amp;#x60;Remainder = ${remainder}&amp;#x60;) // Remainder = 1&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This syntactic sugar is called &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring&quot;&gt;Object Destructuring Assignment&lt;/a&gt;. With this approach we are now independent from the position of return values (we can swap the position of &lt;code&gt;quotient&lt;/code&gt; and &lt;code&gt;remainder&lt;/code&gt; without side effects). This syntax also lets you rename the destructured variables, which can very useful to avoid name collisions with other local variables, or just to make variable names shorter or more descriptive as we please. Let’s see how this works:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;remainder&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;quotient&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;q&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;intDiv&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`Quotient = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;q&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Quotient = 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`Remainder = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;r&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Remainder = 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const { remainder: r, quotient: q } = intDiv(10, 3)console.log(&amp;#x60;Quotient = ${q}&amp;#x60;) // Quotient = 3console.log(&amp;#x60;Remainder = ${r}&amp;#x60;) // Remainder = 1&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Here we are not dependent by values position, but by their names in the returned object. If you are designing an API with multiple return values, it’s up to you to figure out which trade off will be the best to guarantee a proper developer experience.&lt;/p&gt;
&lt;p&gt;Ok, now you should have a good idea on how to simulate multiple return values in JavaScript. In the next section we will see some more realistic examples that take advantage of this pattern.&lt;/p&gt;
&lt;h2 id=&quot;some-more-realistic-use-cases&quot;&gt;Some more realistic use cases&lt;/h2&gt;
&lt;p&gt;As mentioned early on, this technique has been recently popularized by React hooks, so we are gonna explore this use case first. Later we will see other two cases related to Async/Await.&lt;/p&gt;
&lt;h3 id=&quot;react-hooks&quot;&gt;React Hooks&lt;/h3&gt;
&lt;p&gt;React hooks are a &lt;a href=&quot;https://reactjs.org/docs/hooks-overview.html&quot;&gt;new feature proposal&lt;/a&gt; available from &lt;em&gt;React v16.7.0-alpha&lt;/em&gt; that lets you use state and other React features without having to write a class.&lt;/p&gt;
&lt;p&gt;The first and most famous React hook present is called &lt;strong&gt;State Hook&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Let’s see how it works with an example, let’s build a CSS color viewer component.&lt;/p&gt;
&lt;p&gt;Here’s how our component is going to look like:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;CssColorViewer React component demo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;256&quot; height=&quot;252&quot; src=&quot;https://loige.co/_astro/css-color-viewer-demo.BMXrr0-B_2unqxp.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;And here’s the code used to implement this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;useState&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;react&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;CssColorViewer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;cssColor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;setCssColor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;useState&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Blue&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//                          &amp;#x3C;-- multiple return values&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;onCssColorChange&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;setCssColor&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;cssColor&lt;/span&gt;&lt;span style=&quot;--0:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;onChange&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;onCssColorChange&lt;/span&gt;&lt;span style=&quot;--0:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;width&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;height&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;background&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;cssColor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;/&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { useState } from &amp;#x27;react&amp;#x27;function CssColorViewer() {  const [cssColor, setCssColor] = useState(&amp;#x27;Blue&amp;#x27;)  //                          &lt;-- multiple return values  const onCssColorChange = e =&gt; {    setCssColor(e.target.value)  }  return (    &lt;div&gt;      &lt;input value={cssColor} onChange={onCssColorChange} /&gt;      &lt;div        style={{          width: 100,          height: 100,          background: cssColor,        }}      /&gt;    &lt;/div&gt;  )}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;You can see this component in action and play with the code on &lt;a href=&quot;https://codesandbox.io/s/9lzyov54lr&quot;&gt;CodeSandbox&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For the sake of this article, we are going to focus only on the &lt;code&gt;useState&lt;/code&gt; call, but if you are curious to understand better how the hook itself works internally I really recommend you read the &lt;a href=&quot;https://reactjs.org/docs/hooks-state.html&quot;&gt;official State Hook documentation&lt;/a&gt;. I was personally curious to understand how multiple &lt;code&gt;useState&lt;/code&gt; calls could maintain the relationship with the specific state attribute (since there’s no explicit labelling or reference). If you are curious about that too, well you should read the &lt;a href=&quot;https://reactjs.org/docs/hooks-faq.html#how-does-react-associate-hook-calls-with-components&quot;&gt;Hooks FAQ&lt;/a&gt; and &lt;a href=&quot;https://medium.com/@dan_abramov/making-sense-of-react-hooks-fdbde8803889&quot;&gt;Dan Abramov’s recent article about Hooks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Back to the &lt;code&gt;useState&lt;/code&gt; call in our example, now!&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;useState&lt;/code&gt; hook acts like a factory: given a default value for the state property (&lt;code&gt;&apos;Blue&apos;&lt;/code&gt; in our case), it will need to instantiate for you 2 things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the current value for the specific state property (&lt;code&gt;cssColor&lt;/code&gt; in our case)&lt;/li&gt;
&lt;li&gt;a function that allows you to alter the specific property (&lt;code&gt;setCssColor&lt;/code&gt; in our case)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;React developers decided to handle this requirement by simulating multiple return values with an array.&lt;/p&gt;
&lt;p&gt;Combining this with array destructuring and proper variable naming, the result is an API that is very nice to read and to use.&lt;/p&gt;
&lt;p&gt;This React feature is still very experimental and subject to change at the time of writing, but it already sounds like a big deal for the React community to make the code more expressive and reduce the barrier to entry to start adopting React.&lt;/p&gt;
&lt;p&gt;The point I want to make is that, in this specific case, the multiple return values pattern plays a big role towards this goal.&lt;/p&gt;
&lt;h3 id=&quot;converting-callbacks-api-to-asyncawait&quot;&gt;Converting callbacks API to Async/Await&lt;/h3&gt;
&lt;p&gt;Recently I found another great use case for the multiple return values pattern while trying to convert a callback oriented API into an equivalent Async/Await API.&lt;/p&gt;
&lt;p&gt;To make this part clear, I am going to explain very quickly an approach I use to convert callback based APIs into functions that I can use with Async/Await.&lt;/p&gt;
&lt;p&gt;Let’s take this generic example:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;doSomething&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;callback&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ... do something asynchronously and&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//     compute response or error&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// When finished, invoke the callback:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;callback&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;function doSomething(input, callback) {  // ... do something asynchronously and  //     compute response or error  // When finished, invoke the callback:  callback(error, response)}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;To convert this function into something that can be used with Async/Await we have to essentially &lt;a href=&quot;https://loige.co/to-promise-or-to-callback-that-is-the-question/&quot;&gt;&lt;em&gt;promisify&lt;/em&gt;&lt;/a&gt; it. There are libraries to do it and, if you are using Node.js you can even use the builtin &lt;a href=&quot;https://nodejs.org/api/util.html#util_util_promisify_original&quot;&gt;&lt;code&gt;util.promisify&lt;/code&gt;&lt;/a&gt;, but that’s something we can do ourselves by just creating a &lt;em&gt;wrapper&lt;/em&gt; function like the following one:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;doSomethingPromise&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;reject&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;doSomething&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;reject&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const doSomethingPromise = (input) =&gt; new Promise((resolve, reject) =&gt; {  doSomething(input, (error response) =&gt; {    if (error) {      return reject(error)    }    return resolve(response)  })})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In short, our wrapper function &lt;code&gt;doSomethingPromise&lt;/code&gt; is immediately returning a &lt;code&gt;Promise&lt;/code&gt;. Inside the body of the promise we are invoking the original &lt;code&gt;doSomething&lt;/code&gt; function with a callback that will be resolving or rejecting the promise based on whether there’s an &lt;code&gt;error&lt;/code&gt; or not.&lt;/p&gt;
&lt;p&gt;Now we can finally take advantage of Async/Await:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// inside an async function&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;doSomethingPromise&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// inside an async functionconst response = await doSomethingPromise(input)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: this will throw in case of error, so make sure you have it in a &lt;code&gt;try/catch&lt;/code&gt; block to handle the error correctly.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you are curious about &lt;em&gt;promisifying&lt;/em&gt; callback-based functions, I have &lt;a href=&quot;https://loige.co/to-promise-or-to-callback-that-is-the-question/&quot;&gt;an entire article&lt;/a&gt; dedicated to this topic.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In my specific use case, I was using a &lt;a href=&quot;https://www.npmjs.com/package/twitter&quot;&gt;twitter client&lt;/a&gt; library that follows this conventions:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// client is an instance of the twitter client&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;client&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;statuses/user_timeline&apos;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;callback&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;tweets&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;response&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;tweets&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// client is an instance of the twitter clientclient.get(&amp;#x27;statuses/user_timeline&amp;#x27;, params, function callback(  error,  tweets,  response) {  if (!error) {    console.log(tweets)  }})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The important detail here is that the &lt;code&gt;callback&lt;/code&gt; function is a bit unconventional because it receives 3 parameters: a possible &lt;code&gt;error&lt;/code&gt;, a list of &lt;code&gt;tweets&lt;/code&gt; and a &lt;code&gt;response&lt;/code&gt; (which represents the raw HTTP response object). Conventional callback-style APIs will send only two parameters to the callback function: a potential error and some sort of result object.&lt;/p&gt;
&lt;p&gt;The question here is: how to &lt;em&gt;promisify&lt;/em&gt; this unconventional API?&lt;/p&gt;
&lt;p&gt;Multiple return values to the rescue!&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getUserTimeline&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;client&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;reject&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;client&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;statuses/user_timeline&apos;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;tweets&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;reject&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;tweets&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;]) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// multiple return values&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const getUserTimeline = (client, params) =&gt;  new Promise((resolve, reject) =&gt; {    client.get(&amp;#x27;statuses/user_timeline&amp;#x27;, params, (error, tweets, response) =&gt; {      if (error) {        return reject(error)      }      return resolve([tweets, response]) // multiple return values    })  })&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We can use this function with Async/Await as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// inside an async function&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ... set `client` and `params`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;tweets&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getUserTimeline&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;client&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// inside an async function// ... set &amp;#x60;client&amp;#x60; and &amp;#x60;params&amp;#x60;const [tweets, response] = await getUserTimeline(client, params)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: don’t forget to have a &lt;code&gt;try/catch&lt;/code&gt; to handle errors!&lt;/p&gt;
&lt;p&gt;To recap, we can use the multiple return values pattern also with promises to allow them to be resolved to multiple values. This technique gives us a very nice interface especially when used in combination with Async/Await.&lt;/p&gt;
&lt;h3 id=&quot;asyncawait-with-alternative-error-handling&quot;&gt;Async/Await with alternative error handling&lt;/h3&gt;
&lt;p&gt;Another closely related pattern I am seeing more and more in JavaScript is error propagation and handling &lt;em&gt;à la Go&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In Go, when a function can generate an error, this error is not thrown but simply returned by the function. If the function has to return some output and can also generate errors, then the function will have multiple return values (output and error).&lt;/p&gt;
&lt;p&gt;The caller code, should ideally verify if the returned error value is an actual error before proceeding, as in the following Go code example:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;file&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; := &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;os&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Open&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;file.go&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; != &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Fatal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ... do something with `file`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;file, err := os.Open(&amp;#x22;file.go&amp;#x22;)if err != nil {  log.Fatal(err)}// ... do something with &amp;#x60;file&amp;#x60;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Some JavaScript libraries are starting to promote the same conventions as in Go to report errors, especially when it comes to Async/Await.&lt;/p&gt;
&lt;p&gt;You can find some examples by just &lt;a href=&quot;https://github.com/search?l=JavaScript&amp;#x26;q=%22error+%3D+await%22&amp;#x26;type=Code&quot;&gt;searching &lt;code&gt;&quot;error = await&quot;&lt;/code&gt; on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let’s rewrite our &lt;code&gt;getUserTimeline&lt;/code&gt; function from our previous example to follow this approach:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getUserTimeline&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;client&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;reject&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;client&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;statuses/user_timeline&apos;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;tweets&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;tweets&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;]) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// multiple return values&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const getUserTimeline = (client, params) =&gt;  new Promise((resolve, reject) =&gt; {    client.get(&amp;#x27;statuses/user_timeline&amp;#x27;, params, (error, tweets, response) =&gt; {      return resolve([error, tweets, response]) // multiple return values    })  })&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Notice that we are never telling the promise to &lt;em&gt;reject&lt;/em&gt;, so when we will be using this function with Async/Await we cannot use try/catch to handle errors. This is what we should do instead:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// inside an async function&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ... set `client` and `params`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;tweets&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getUserTimeline&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;client&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;params&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// handle error here&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ... do stuff with `tweets` and `response`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// inside an async function// ... set &amp;#x60;client&amp;#x60; and &amp;#x60;params&amp;#x60;const [error, tweets, response] = await getUserTimeline(client, params)if (error) {  // handle error here}// ... do stuff with &amp;#x60;tweets&amp;#x60; and &amp;#x60;response&amp;#x60;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;I am not sure if I would recommend this pattern or not in JavaScript land. I have a bit of mixed feelings about it. On one side I quite like it, because as happens in Go, it forces you to handle every single error individually, which makes you think a bit more carefully about the best way to handle the specifics of the error. On the other hand, this pattern it still feels a bit forced into JavaScript and people that never saw this pattern in other languages might find it annoying or even hard to understand. Moreover, if you don’t capture and handle an error this will not automatically escalate (as it happens with &lt;code&gt;throw&lt;/code&gt; or rejected promises), so the error will totally be swallowed by the runtime, leading to potential inconsistencies in your app state.
I’ll let you draw your own conclusions on this one! 😇&lt;/p&gt;
&lt;h2 id=&quot;array-destructuring-tricks&quot;&gt;Array destructuring tricks&lt;/h2&gt;
&lt;p&gt;At this point, I would like to show you few &lt;em&gt;“little tricks”&lt;/em&gt; that you can use with array destructuring that might come in handy when dealing with multiple return values.&lt;/p&gt;
&lt;h3 id=&quot;skipping-elements&quot;&gt;Skipping elements&lt;/h3&gt;
&lt;p&gt;Let’s say, for instance, that you have a function &lt;code&gt;doStuff&lt;/code&gt; that returns multiple values using an array and the values are in the array are an &lt;code&gt;error&lt;/code&gt;, a &lt;code&gt;rawResponse&lt;/code&gt; and &lt;code&gt;result&lt;/code&gt;. Let’s say only for the sake of this example that you are not interested in using the &lt;code&gt;rawResponse&lt;/code&gt;, you could easily skip that element while destructuring with the following syntax:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, , &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;doStuff&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const [error, , result] = doStuff()&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Notice the double comma there. That basically means that we are leaving an array index unassigned. You can bend this technique as you please, for example you might decide to destructure only the &lt;code&gt;result&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [, , &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;doStuff&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const [, , result] = doStuff()&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Well, you shouldn’t really skip errors though…&lt;/p&gt;
&lt;h3 id=&quot;aggregate-remaining-return-values&quot;&gt;Aggregate remaining return values&lt;/h3&gt;
&lt;p&gt;Another interesting trick is that you can use the special &lt;code&gt;...&lt;/code&gt; syntax to accumulate the &lt;em&gt;remaining return values&lt;/em&gt; under a single variable. Let’s make a dummy example to explore this idea.&lt;/p&gt;
&lt;p&gt;Let’s say we have a function called &lt;code&gt;listDogs&lt;/code&gt; which is implemented as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;listDogs&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Bella&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Lucy&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Daisy&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;function listDogs() {  return [3, &amp;#x27;Bella&amp;#x27;, &amp;#x27;Lucy&amp;#x27;, &amp;#x27;Daisy&amp;#x27;]}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The first element of the array is the number of dogs, while every other elements are actual dog names.&lt;/p&gt;
&lt;p&gt;Since the number of returned elements here is variable it might be tricky to use destructuring directly. In these cases we can use this special syntax:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;numDogs&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;dogNames&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;listDogs&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;numDogs&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;dogNames&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// [ &apos;Bella&apos;, &apos;Lucy&apos;, &apos;Daisy&apos; ]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const [numDogs, ...dogNames] = listDogs()console.log(numDogs) // 3console.log(dogNames) // [ &amp;#x27;Bella&amp;#x27;, &amp;#x27;Lucy&amp;#x27;, &amp;#x27;Daisy&amp;#x27; ]&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;...&lt;/code&gt; syntax basically allows you to destructure any remaining element of the array into another array. Of course you can only have a &lt;code&gt;...&lt;/code&gt; element in the left hand side of the destructuring expression and this has to be the last element in the list.&lt;/p&gt;
&lt;p&gt;My example here is very dummy, but this pattern really shines in some real life use cases, for example when you want to &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Unpacking_values_from_a_regular_expression_match&quot;&gt;unpack values from a regular expression match&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;performance-implications&quot;&gt;Performance implications&lt;/h2&gt;
&lt;p&gt;When React hooks were presented the community was super excited about this new feature, but some performance experts in the Google chromium team (&lt;a href=&quot;https://twitter.com/bmeurer&quot;&gt;@bmeurer&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/_developit&quot;&gt;@_developit&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/rossmcilroy&quot;&gt;@rossmcilroy&lt;/a&gt;) raised their eyebrows and wanted to dig deeper to see if this new approach could lead to serious performance issues in the web.&lt;/p&gt;
&lt;p&gt;What came out from their research is an amazing paper that goes by the title &lt;a href=&quot;https://docs.google.com/document/d/1hWb-lQW4NSG9yRpyyiAA_9Ktytd5lypLnVLhPX9vamE/edit&quot;&gt;“Array destructuring for multi-value returns (in light of React hooks)”&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I really encourage you to read it to get all the details, but here’s my attempt at giving you some sort of TLDR;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In React components the &lt;code&gt;render()&lt;/code&gt; method is called often, so the code there should be optimized enough not to slow things down. That’s where you use React hooks.&lt;/li&gt;
&lt;li&gt;Array destructuring is a very generic API, it doesn’t work only with arrays but with every type of &lt;em&gt;iterable&lt;/em&gt; object, so the VM has a lot work to do to figure out how to traverse and destructure the specific object.&lt;/li&gt;
&lt;li&gt;Object destructuring might be a more performant alternative, but it would probably offer a less pleasant developer experience.&lt;/li&gt;
&lt;li&gt;If you use Babel in loose mode, array destructuring will be highly simplified (to direct element access) and it will result in highly optimized code.&lt;/li&gt;
&lt;li&gt;There’s work going on to see if the different phases of the optimizing compiler in the Google’s V8 engine might be able to optimize destructuring even if you are not using Babel.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;recap&quot;&gt;Recap&lt;/h2&gt;
&lt;p&gt;In this article we discussed this new emerging JavaScript pattern that is getting more and more traction, mostly because of its adoption within React.&lt;/p&gt;
&lt;p&gt;Use cases are not limited to React though and I hope you will find this useful in your daily development life also outside the React land.&lt;/p&gt;
&lt;p&gt;I am really curious to see what you will come up with, so please keep me in the loop using &lt;a href=&quot;https://twitter.com/loige&quot;&gt;twitter&lt;/a&gt; or the comments in this article.&lt;/p&gt;
&lt;p&gt;For the very curious ones I want to give you one last link, so that you can compare &lt;a href=&quot;https://rosettacode.org/wiki/Return_multiple_values&quot;&gt;how multiple return values are implemented in many many other languages&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Until next time!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/emerging-javascript-pattern-multiple-return-values.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/emerging-javascript-pattern-multiple-return-values.png" width="1200" height="630"/></media:content><category>javascript</category><category>node-js</category><category>design-patterns</category><category>react</category><category>lua</category><category>go</category><author>Luciano Mammino</author><comments>https://loige.co/emerging-javascript-pattern-multiple-return-values/#comments</comments><enclosure url="https://loige.co/og/emerging-javascript-pattern-multiple-return-values.png" length="0" type="image/png"/></item><item><title>How to to_string in Rust</title><link>https://loige.co/how-to-to-string-in-rust/</link><guid isPermaLink="true">https://loige.co/how-to-to-string-in-rust/</guid><description>This article explores how to convert values to strings in Rust using traits like Debug, Display and ToString. It explains the difference between user-facing and debug representations.</description><pubDate>Wed, 26 May 2021 18:50:00 GMT</pubDate><content:encoded>&lt;p&gt;In Rust, there are several ways to turn a value into a string. In this article, we will explore a few different ways and discuss what are the most idiomatic approaches depending on the context you are currently working on.&lt;/p&gt;
&lt;p&gt;Personally, I have been quite confused for a while on what’s the best way to implement a “to string” functionality for a given Rust struct. The reason why this has been confusing to me is that there are indeed many ways to do that and they all have different purposes.&lt;/p&gt;
&lt;p&gt;I finally decided to do a bit of research to try and demystify this topic a bit and, in this post, I want to share what I learned!&lt;/p&gt;
&lt;p&gt;Are you ready? 🙂&lt;/p&gt;
&lt;h2 id=&quot;implementing-our-own-to_string&quot;&gt;Implementing our own &lt;code&gt;to_string()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Coming from other languages and not having a deep knowledge of the most idiomatic Rust approaches, the first thing that I generally tend to do when facing a problem is &lt;em&gt;“let’s just make this work for now”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So, in the spirit of &lt;em&gt;just making things work&lt;/em&gt;, the first thing that we can do is to &lt;em&gt;just&lt;/em&gt; implement our own &lt;code&gt;to_string()&lt;/code&gt; method on a given struct.&lt;/p&gt;
&lt;p&gt;At the end of the day, what we want is just to be able to turn a given value into a &lt;code&gt;String&lt;/code&gt; value, essentially something like:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;someValue.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;to_string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// returns a String value&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;someValue.to_string(); // returns a String value&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;For the sake of having a consistent example throughout the article, let’s pretend that we are working on a struct that allows us to manage API credentials. In this context credentials are made up of 2 separate values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An &lt;code&gt;api_key&lt;/code&gt;: effectively a unique id for the key.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;secret&lt;/code&gt;: a secret string associated with the key. Something that we could use to sign API requests.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can store this data in a struct called &lt;code&gt;Credentials&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;api_key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;secret&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;pub struct Credentials {    api_key: String,    secret: String,}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Ok, now let’s add a constructor and a &lt;code&gt;to_string&lt;/code&gt; method to this struct:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;api_key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;secret&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;api_key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;secret&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;to_string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// We don&apos;t want to disclose the secret&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;format!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Credentials({})&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.api_key)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;impl Credentials {    pub fn new(api_key: String, secret: String) -&gt; Self {        Credentials {            api_key,            secret,        }    }    pub fn to_string(&amp;#x26;self) -&gt; String {        // We don&amp;#x27;t want to disclose the secret        format!(&amp;#x22;Credentials({})&amp;#x22;, &amp;#x26;self.api_key)    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Quick note: the &lt;code&gt;secret&lt;/code&gt; is a piece of sensitive information, so it makes sense not to print it out in our &lt;code&gt;to_string()&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;Now, we can use our new struct:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;creds&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;SOME_API_KEY&quot;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;SOME_SECRET&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;creds&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;to_string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;fn main() {    let creds = Credentials::new(String::from(&amp;#x22;SOME_API_KEY&amp;#x22;), String::from(&amp;#x22;SOME_SECRET&amp;#x22;));    println!(&amp;#x22;{}&amp;#x22;, creds.to_string());}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The snippet above is going to print:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Credentials(SOME_API_KEY)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Credentials(SOME_API_KEY)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Success! 🎉&lt;/p&gt;
&lt;p&gt;OK, this is easy and it works! But, let’s face it, the implementation is very specific to our struct!&lt;/p&gt;
&lt;p&gt;What I mean by that is that the rest of the codebase doesn’t really know that this type can be converted to a String. It is just a method like any other and there is no agreement or standard that says that this is how you &lt;em&gt;signal&lt;/em&gt; that a given value can be converted to a string. Therefore, we cannot build abstractions on top of this…&lt;/p&gt;
&lt;p&gt;In fact, note how we needed to explicitly call &lt;code&gt;to_string()&lt;/code&gt; in our &lt;code&gt;println!()&lt;/code&gt; call.&lt;/p&gt;
&lt;p&gt;If we try to remove that and just pass the &lt;code&gt;creds&lt;/code&gt; value we get an error:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;error[E0277]: `Credentials` doesn&apos;t implement `std::fmt::Display`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;--&gt; src/main.rs:22:20&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;22 |     println!(&quot;{}&quot;, creds);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|                    ^^^^^ `Credentials` cannot be formatted with the default formatter&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;|&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;= help: the trait `std::fmt::Display` is not implemented for `Credentials`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;= note: required by `std::fmt::Display::fmt`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;   &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;error: aborting due to previous error&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;For more information about this error, try `rustc --explain E0277`.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;error[E0277]: &amp;#x60;Credentials&amp;#x60; doesn&amp;#x27;t implement &amp;#x60;std::fmt::Display&amp;#x60;  --&gt; src/main.rs:22:20   |22 |     println!(&amp;#x22;{}&amp;#x22;, creds);   |                    ^^^^^ &amp;#x60;Credentials&amp;#x60; cannot be formatted with the default formatter   |   = help: the trait &amp;#x60;std::fmt::Display&amp;#x60; is not implemented for &amp;#x60;Credentials&amp;#x60;   = note: in format strings you may be able to use &amp;#x60;{:?}&amp;#x60; (or {:#?} for pretty-print) instead   = note: required by &amp;#x60;std::fmt::Display::fmt&amp;#x60;   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)error: aborting due to previous errorFor more information about this error, try &amp;#x60;rustc --explain E0277&amp;#x60;.&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If we zoom in a little, the error message is clear:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&quot;`Credentials` cannot be formatted with the default formatter&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&amp;#x22;&amp;#x60;Credentials&amp;#x60; cannot be formatted with the default formatter&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;As expected, the Rust compiler doesn’t seem to understand that we have defined a way to turn &lt;code&gt;Credentials&lt;/code&gt; values into a string!&lt;/p&gt;
&lt;p&gt;Wouldn’t it be nice if we could somehow tell the Rust compiler that our &lt;code&gt;Credentials&lt;/code&gt; type can be &lt;em&gt;stringified&lt;/em&gt;?&lt;/p&gt;
&lt;h2 id=&quot;rust-traits&quot;&gt;Rust traits&lt;/h2&gt;
&lt;p&gt;If we have a second, more in-depth, look at the error above, there’s an interesting hint there:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;the trait `std::fmt::Display` is not implemented for `Credentials`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;the trait &amp;#x60;std::fmt::Display&amp;#x60; is not implemented for &amp;#x60;Credentials&amp;#x60;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The Rust compiler is trying to be helpful and it’s telling us:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“You know, if you want to be able to automatically convert &lt;code&gt;Credentials&lt;/code&gt; values to a string, you should look into implementing the &lt;code&gt;std::fmt::Display&lt;/code&gt; trait”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In Rust, structs can expose certain common behavior by implementing specific traits.&lt;/p&gt;
&lt;p&gt;In other languages, you can do the same by extending certain classes or implementing certain interfaces. Other languages do the same by convention (or by protocols): if you implement certain methods with very specific names, arguments, and return types then your type (or object) can exhibit a certain behavior.&lt;/p&gt;
&lt;p&gt;Regarding the &lt;em&gt;“to string behavior&lt;/em&gt;”, in Rust, there are several interesting traits that we should look into!&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;the &lt;code&gt;std::fmt::Debug&lt;/code&gt; trait&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;std::string::ToString&lt;/code&gt; trait&lt;/li&gt;
&lt;li&gt;the s&lt;code&gt;td::fmt::Display&lt;/code&gt; trait (the one recommended by the previous error message)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;They have very specific purposes, so in the rest of this article, we will be exploring all of them and discuss when you should be using them.&lt;/p&gt;
&lt;h2 id=&quot;the-debug-trait&quot;&gt;The &lt;code&gt;Debug&lt;/code&gt; trait&lt;/h2&gt;
&lt;p&gt;Let’s start with the &lt;code&gt;Debug&lt;/code&gt; trait.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://doc.rust-lang.org/std/fmt/trait.Debug.html&quot;&gt;&lt;code&gt;Debug&lt;/code&gt; documentation&lt;/a&gt; says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Debug should format the output in a programmer-facing, debugging context”.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a great way to provide details about a struct, providing a message that should be visible only to developers in a debugging context.&lt;/p&gt;
&lt;p&gt;An interesting thing is that we can get Rust to auto-implement the &lt;code&gt;Debug&lt;/code&gt; trait for us by using the &lt;code&gt;Derive&lt;/code&gt; macro:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;#[derive(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Debug&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;SomeStruct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;#[derive(Debug)]struct SomeStruct{}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;So, if we want to implement the &lt;code&gt;Debug&lt;/code&gt; trait in our example, we could do it as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;#[derive(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Debug&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;api_key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;secret&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;api_key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;secret&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;api_key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;secret&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;creds&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;SOME_API_KEY&quot;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;SOME_SECRET&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{:?}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;creds&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;#[derive(Debug)]pub struct Credentials {    api_key: String,    secret: String,}impl Credentials {    pub fn new(api_key: String, secret: String) -&gt; Self {        Credentials {            api_key,            secret,        }    }}fn main() {    let creds = Credentials::new(String::from(&amp;#x22;SOME_API_KEY&amp;#x22;), String::from(&amp;#x22;SOME_SECRET&amp;#x22;));    println!(&amp;#x22;{:?}&amp;#x22;, creds);}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The code above will output:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Credentials { api_key: &quot;SOME_API_KEY&quot;, secret: &quot;SOME_SECRET&quot; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Credentials { api_key: &amp;#x22;SOME_API_KEY&amp;#x22;, secret: &amp;#x22;SOME_SECRET&amp;#x22; }&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Did you notice that we used the &lt;code&gt;{:?}&lt;/code&gt; placeholder in our format string? This is the placeholder that indicates you want to print the value in &lt;em&gt;“debug mode”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;A small productivity tip here: you can also use the &lt;code&gt;{:#?}&lt;/code&gt; placeholder (note the hash) if you want the output to be pretty-printed! If we do that in our with our &lt;code&gt;Credentials&lt;/code&gt; struct from the previous example, it will be printed like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Credentials {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;api_key: &quot;SOME_API_KEY&quot;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;secret: &quot;SOME_SECRET&quot;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Credentials {    api_key: &amp;#x22;SOME_API_KEY&amp;#x22;,    secret: &amp;#x22;SOME_SECRET&amp;#x22;,}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;But what if we want to customize the string generated in &lt;em&gt;“debug mode”&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;For instance, we might not want to display the full &lt;code&gt;secret&lt;/code&gt; but only the first 4 characters and obfuscate all the remaining ones with asterisks.&lt;/p&gt;
&lt;p&gt;Well, in this particular case, we can implement the &lt;code&gt;Debug&lt;/code&gt; trait manually:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;std&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::fmt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;api_key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;secret&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;api_key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;secret&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;api_key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;secret&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Debug&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;mut&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Formatter&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;debug_struct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Credentials&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;field&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;api_key&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.api_key)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;field&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;                &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;secret&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.secret&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;chars&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;enumerate&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(|(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)| &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &amp;#x3C; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;c&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;collect&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;finish&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;creds&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;SOME_API_KEY&quot;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;SOME_SECRET&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{:#?}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;creds&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;use std::fmt;pub struct Credentials {    api_key: String,    secret: String,}impl Credentials {    pub fn new(api_key: String, secret: String) -&gt; Self {        Credentials { api_key, secret }    }}impl fmt::Debug for Credentials {    fn fmt(&amp;#x26;self, f: &amp;#x26;mut fmt::Formatter) -&gt; fmt::Result {        f.debug_struct(&amp;#x22;Credentials&amp;#x22;)            .field(&amp;#x22;api_key&amp;#x22;, &amp;#x26;self.api_key)            .field(                &amp;#x22;secret&amp;#x22;,                &amp;#x26;self                    .secret                    .chars()                    .enumerate()                    .map(|(i, c)| if i &lt; 4 { c } else { &amp;#x27;*&amp;#x27; })                    .collect::&lt;String&gt;(),            )            .finish()    }}fn main() {    let creds = Credentials::new(String::from(&amp;#x22;SOME_API_KEY&amp;#x22;), String::from(&amp;#x22;SOME_SECRET&amp;#x22;));    println!(&amp;#x22;{:#?}&amp;#x22;, creds);}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The code above will output:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Credentials {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;api_key: &quot;SOME_API_KEY&quot;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;secret: &quot;SOME*******&quot;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Credentials {    api_key: &amp;#x22;SOME_API_KEY&amp;#x22;,    secret: &amp;#x22;SOME*******&amp;#x22;,}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Implementing the &lt;code&gt;Debug&lt;/code&gt; trait manually is something that you rarely have to do manually. For the majority of use cases, the &lt;code&gt;Derive&lt;/code&gt; macro will serve you well!&lt;/p&gt;
&lt;p&gt;It is interesting to note that implementing the Debug trait manually requires you to use a &lt;code&gt;Formatter&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;From the documentation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“A Formatter represents various options related to formatting. Users do not construct Formatters directly; a mutable reference to one is passed to the fmt method of all formatting traits, like Debug and Display.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In short, a formatter is a utility that helps you to build the output string you want to generate. If you are curious to find out more, you can check out the &lt;a href=&quot;https://doc.rust-lang.org/std/fmt/struct.Formatter.html&quot;&gt;official documentation page on the &lt;code&gt;Formatter&lt;/code&gt; type&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-tostring-trait&quot;&gt;The &lt;code&gt;ToString&lt;/code&gt; trait&lt;/h2&gt;
&lt;p&gt;Let’s now talk about the &lt;code&gt;std::string::ToString&lt;/code&gt; trait, which is defined as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“A trait for converting a value to a String”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But the documentation also says that &lt;strong&gt;this trait shouldn’t be implemented directly&lt;/strong&gt;. The &lt;code&gt;Display&lt;/code&gt; trait should be implemented instead and by doing that you get the &lt;code&gt;ToString&lt;/code&gt; implementation for free!&lt;/p&gt;
&lt;p&gt;How is that possible? I mean, how is it possible that by implementing a trait, we get another one implemented automatically?&lt;/p&gt;
&lt;p&gt;In Rust, we can implement a trait for any type that implements another trait. Implementations of a trait on any type that satisfies the trait bounds are called &lt;strong&gt;blanket implementations&lt;/strong&gt; and are extensively used in the Rust standard library.&lt;/p&gt;
&lt;p&gt;What this means in practice is that somewhere in the Rust core library there is some code like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Display&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;ToString&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;to_string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// blanket implementation here...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;impl&lt;T: Display&gt; ToString for T {    fn to_string(&amp;#x26;self) -&gt; String {        // blanket implementation here...    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This is basically telling the Rust compiler how to provide a &lt;em&gt;default&lt;/em&gt; implementation of the &lt;code&gt;ToString&lt;/code&gt; trait for any generic types &lt;code&gt;T&lt;/code&gt; that implements the &lt;code&gt;Display&lt;/code&gt; trait.&lt;/p&gt;
&lt;p&gt;Implementing &lt;code&gt;ToString&lt;/code&gt; for a type will force that type to have a &lt;code&gt;to_string()&lt;/code&gt; method. But the more idiomatic way to tell Rust that a type can have a user-facing string representation is to implement the more generic &lt;code&gt;Display&lt;/code&gt; trait.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: It’s is interesting to know that the &lt;code&gt;Display&lt;/code&gt; trait is implemented in the &lt;code&gt;core&lt;/code&gt; module and does not use any memory allocator. &lt;code&gt;String&lt;/code&gt; is heap-allocated, so it couldn’t have been used in &lt;code&gt;Display&lt;/code&gt;’s definition. Rust designs traits carefully to keep &lt;em&gt;heap allocating&lt;/em&gt; functions separated from the ones that don’t need a memory allocator (&lt;code&gt;core&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Thanks to &lt;a href=&quot;https://lobste.rs/s/7hrgbb/how_string_rust#c_cxqzse&quot;&gt;kornel&lt;/a&gt; from lobste.rs for this tip&lt;/small&gt;.&lt;/p&gt;
&lt;p&gt;At this point, we can practically ignore the &lt;code&gt;ToString&lt;/code&gt; trait and focus only on the &lt;code&gt;Display&lt;/code&gt; trait!&lt;/p&gt;
&lt;h2 id=&quot;the-display-trait&quot;&gt;The &lt;code&gt;Display&lt;/code&gt; trait&lt;/h2&gt;
&lt;p&gt;From &lt;a href=&quot;https://doc.rust-lang.org/std/fmt/trait.Display.html&quot;&gt;the official &lt;code&gt;Display&lt;/code&gt; documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Display is similar to Debug, but Display is for user-facing output, and so cannot be derived”.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The documentation is essentially saying that &lt;code&gt;Display&lt;/code&gt; allows us to provide a user-facing description of a type and that we can only implement the trait directly, no magic derive!&lt;/p&gt;
&lt;p&gt;Let’s implement &lt;code&gt;Display&lt;/code&gt; for our &lt;code&gt;Credentials&lt;/code&gt; struct then:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;std&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::fmt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;api_key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;secret&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;api_key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;secret&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;api_key&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;secret&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Display&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;mut&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Formatter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;write_str&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.api_key.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;as_ref&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;creds&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;SOME_API_KEY&quot;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;SOME_SECRET&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;creds&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// &quot;SOME_API_KEY&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;use std::fmt;pub struct Credentials {    api_key: String,    secret: String,}impl Credentials {    pub fn new(api_key: String, secret: String) -&gt; Self {        Credentials { api_key, secret }    }}impl fmt::Display for Credentials {    fn fmt(&amp;#x26;self, f: &amp;#x26;mut fmt::Formatter&lt;&amp;#x27;_&gt;) -&gt; fmt::Result {        f.write_str(self.api_key.as_ref())    }}fn main() {    let creds = Credentials::new(String::from(&amp;#x22;SOME_API_KEY&amp;#x22;), String::from(&amp;#x22;SOME_SECRET&amp;#x22;));    println!(&amp;#x22;{}&amp;#x22;, creds); // &amp;#x22;SOME_API_KEY&amp;#x22;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note that, again, we have to deal with a formatter.&lt;/p&gt;
&lt;p&gt;A small productivity tip is that you can use the &lt;code&gt;write!&lt;/code&gt; macro with formatters and convert:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;write_str&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.api_key.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;as_ref&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;f.write_str(self.api_key.as_ref())&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;into:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;write!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.api_key)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;write!(f, &amp;#x22;{}&amp;#x22;, self.api_key)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Nicer and more flexible, isn’t it?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: the &lt;code&gt;Formatter&lt;/code&gt; type is more flexible because it allows us to write data into an arbitrary buffer (rather than always allocating new &lt;code&gt;String&lt;/code&gt;s). For instance we could pre-allocate a buffer once (as a &lt;code&gt;String&lt;/code&gt;) and write onto it multiple times as in the following example:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;std&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Write&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;() -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;foo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;foosecret&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;bar&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Credentials&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;barsecret&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// pre-allocated buffer&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;mut&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;output&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;with_capacity&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;write!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;mut&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;output&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;foo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)?;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;write!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;mut&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;output&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;bar&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)?;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;output&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// foobar&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Ok&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;use std::fmt::Write;fn main() -&gt; fmt::Result {    let foo = Credentials::new(String::from(&amp;#x22;foo&amp;#x22;), String::from(&amp;#x22;foosecret&amp;#x22;));    let bar = Credentials::new(String::from(&amp;#x22;bar&amp;#x22;), String::from(&amp;#x22;barsecret&amp;#x22;));    // pre-allocated buffer    let mut output = String::with_capacity(200);    write!(&amp;#x26;mut output, &amp;#x22;{}&amp;#x22;, foo)?;    write!(&amp;#x26;mut output, &amp;#x22;{}&amp;#x22;, bar)?;    println!(&amp;#x22;{}&amp;#x22;, output); // foobar    Ok(())}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;small&gt;Thanks to &lt;a href=&quot;https://www.reddit.com/r/rust/comments/nlor05/how_to_to_string_in_rust_extended_blog_post_from/gzmc14l&quot;&gt;nicoburns&lt;/a&gt; from Reddit for this tip.&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;Also, remember that the placeholder to use the &lt;code&gt;Display&lt;/code&gt; trait is just &lt;code&gt;{}&lt;/code&gt; (as opposed to &lt;code&gt;{:?}&lt;/code&gt; or &lt;code&gt;{:#?}&lt;/code&gt; for the &lt;code&gt;Debug&lt;/code&gt; trait).&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;So, just to summarise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Debug&lt;/code&gt; allows you to generate a debug representation for a given type. It can be automatically derived.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Display&lt;/code&gt; is the equivalent but for user-facing information. It &lt;strong&gt;CANNOT&lt;/strong&gt; be derived.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ToString&lt;/code&gt;… don’t implement it, just implement &lt;code&gt;Display&lt;/code&gt; and you will get it for free thanks to the standard blanket implementation!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s all I know about stringifying things in Rust! 😊&lt;/p&gt;
&lt;p&gt;I hope this article was insightful and I am curious to know if you learned something new or if all these things were already done and dusted in your Rust journey! Let me know that in the comments!&lt;/p&gt;
&lt;p&gt;Did I miss or misunderstood something? Please, let me know that as well! ❤️&lt;/p&gt;
&lt;p&gt;If you’d like to see more of my Rust learning journey check out my new &lt;a href=&quot;https://www.twitch.tv/loige&quot;&gt;twitch channel&lt;/a&gt;, where I stream every week (Monday 5PM GMT) with my friends &lt;a href=&quot;https://twitter.com/88_eugen&quot;&gt;Eugen&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/gbinside&quot;&gt;Roberto&lt;/a&gt; our attempts at cracking the &lt;a href=&quot;https://github.com/lmammino/rust-advent/tree/main/y2020/ex12&quot;&gt;Advent of code challenges&lt;/a&gt; using Rust!&lt;/p&gt;
&lt;p&gt;And if you prefer to read rather than watching long random-ish streaming sessions, you could check the other &lt;a href=&quot;https://loige.co/tag/rust&quot;&gt;Rust articles in this blog&lt;/a&gt;. There are already a good few! 😱&lt;/p&gt;
&lt;p&gt;CIAO 🙃&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/how-to-to-string-in-rust.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/how-to-to-string-in-rust.png" width="1200" height="630"/></media:content><category>rust</category><author>Luciano Mammino</author><comments>https://loige.co/how-to-to-string-in-rust/#comments</comments><enclosure url="https://loige.co/og/how-to-to-string-in-rust.png" length="0" type="image/png"/></item><item><title>Provision an Ubuntu-based EC2 instance with CDK</title><link>https://loige.co/provision-ubuntu-ec2-with-cdk/</link><guid isPermaLink="true">https://loige.co/provision-ubuntu-ec2-with-cdk/</guid><description>This post explains how to use CDK to provision Ubuntu EC2 instances on AWS. It covers finding the right AMI, adding security groups, using init scripts, installing AWS utilities, and more.</description><pubDate>Fri, 06 Aug 2021 13:05:00 GMT</pubDate><content:encoded>&lt;p&gt;You are using CDK and you need to provision an EC2 instance. What if you prefer to use &lt;strong&gt;Ubuntu&lt;/strong&gt; over &lt;strong&gt;Amazon Linux&lt;/strong&gt;? In this article, we will see exactly how to do that, and, hopefully, we will learn a bunch of interesting things in the process!&lt;/p&gt;
&lt;p&gt;I have to be honest, I am more on the Ubuntu camp than I am in the Amazon Linux one… It’s a subjective preference. I find myself more comfortable with &lt;code&gt;apt&lt;/code&gt;, &lt;code&gt;snap&lt;/code&gt;, &lt;code&gt;systemd&lt;/code&gt; and other Ubuntu nuances than I am with &lt;code&gt;yum&lt;/code&gt; and other things in Amazon Linux. Plus, I find easier to find resources about how to do all sort of things with Ubuntu.&lt;/p&gt;
&lt;p&gt;So, the story goes that I was playing with CDK and I was trying to deploy a simple Node.js application to an EC2 instance. All the CDK examples I could find were using Amazon Linux, but I thought it wouldn’t be too complicated to switch to Ubuntu instead. I already had a Systemd service definition written for my app and a script to install all dependencies using &lt;code&gt;apt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;How hard could it be to use Ubuntu? It turns out there are some dark corners and the necessary documentation is scattered around the web. I will try to document my finding and provide a complete example in this article. We will also see how to install the &lt;code&gt;aws&lt;/code&gt; CLI and other necessary AWS utilities in our Ubuntu-based virtual machine. Once you do all these things, you should have a Ubuntu image that is pretty much on par with the Amazon Linux one.&lt;/p&gt;
&lt;h2 id=&quot;what-is-cdk&quot;&gt;What is CDK&lt;/h2&gt;
&lt;p&gt;Ok, if you know CDK already, you can just skip this section. If you don’t, how on the world wide web did you end up on this page? 😅&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/cdk/&quot;&gt;CDK&lt;/a&gt; stands for &lt;strong&gt;Cloud Development Kit&lt;/strong&gt; and it’s a relatively new tool from Amazon to write infrastructure as code (&lt;em&gt;IaC&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;CDK allows you to define all your cloud infrastructure programmatically so you can keep it versioned and you can have a reproducible deployment process. If you use CDK you won’t have to go in the AWS web console and click around to provision resources, you’ll write code and use command-line tools (or CI/CD pipelines) to do that for you.&lt;/p&gt;
&lt;p&gt;If you have used tools like &lt;strong&gt;Terraform&lt;/strong&gt; or &lt;strong&gt;CloudFormation&lt;/strong&gt; already, CDK addresses the same type of problems. What’s different with CDK is that you don’t have to write a ton of JSON, Yaml or learn a new markup language such as &lt;a href=&quot;https://github.com/hashicorp/hcl&quot;&gt;HCL&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In fact, with CDK you can use your favorite programming language (TypeScript, Python, Java and C# are supported right now) and you can define the resources in your cloud infrastructure by importing classes and instantiating objects.&lt;/p&gt;
&lt;p&gt;Just to give you an example, this is how you can create a new SSM parameter using CDK (TypeScript):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ssm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/aws-ssm&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ssm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;StringParameter&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;stack&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Parameter&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;allowedPattern&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;.*&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;The value Foo&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;parameterName&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;FooParameter&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;stringValue&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Foo&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;tier&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ssm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ParameterTier&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;ADVANCED&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import * as ssm from &amp;#x27;@aws-cdk/aws-ssm&amp;#x27;new ssm.StringParameter(stack, &amp;#x27;Parameter&amp;#x27;, {  allowedPattern: &amp;#x27;.*&amp;#x27;,  description: &amp;#x27;The value Foo&amp;#x27;,  parameterName: &amp;#x27;FooParameter&amp;#x27;,  stringValue: &amp;#x27;Foo&amp;#x27;,  tier: ssm.ParameterTier.ADVANCED,})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;You can see already that the main advantage of CDK is that you’ll be able to use your favorite language, your favorite code editor or IDE and get other nice things like syntax highligting, type checking, auto-completion, etc.&lt;/p&gt;
&lt;p&gt;I have found that there’s much less guesswork or “writing configuration by trial and error” when using CDK as opposed to writing plain CloudFormation configuration or using Terraform.&lt;/p&gt;
&lt;p&gt;It’s worth knowing that CDK is not a standalone tool, but it’s an abstraction built on top of CloudFormation. So when you &lt;em&gt;synthesise&lt;/em&gt; (which is how you say &lt;em&gt;compile&lt;/em&gt; in CDK lingo) a CDK stack, you actually get a CloudFormation stack. When you run &lt;code&gt;cdk deploy&lt;/code&gt; you are actually deploying that stack with CloudFormation. This way, you still get all the benefits of CloudFormation, but you also get a nicer way to write down your infrastructure as code.&lt;/p&gt;
&lt;p&gt;If you want to know how to get started with CDK check out the official guide &lt;a href=&quot;https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html&quot;&gt;Getting started with the AWS CDK&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;defining-an-ec2-resource-with-cdk&quot;&gt;Defining An EC2 resource with CDK&lt;/h2&gt;
&lt;p&gt;From here, I am assuming you have already installed CDK and generated a project with &lt;code&gt;cdk init&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you want to have a look at the final version of the code we will be discussing here, you can check out the &lt;a href=&quot;https://github.com/lmammino/cdk-ubuntu-ec2&quot;&gt;project repository on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To provision an EC2 instance with CDK using TypeScript we need to install the package &lt;code&gt;@aws-cdk/aws-ec2&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--save&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;@aws-cdk/aws-ec2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm i --save @aws-cdk/aws-ec2&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Then we can define the instance in a Stack with the following code (intentionally incomplete):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/core&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/aws-ec2&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;MyAppStack&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Stack&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;defaultVpc&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Vpc&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fromLookup&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;VPC&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;isDefault&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;myVm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Instance&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;myVm&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// the type of instance to deploy (e.g. a &apos;t2.micro&apos;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;instanceType&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;InstanceType&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;t2.micro&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// the id of the image to use for the instance&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;machineImage&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;someAmiId&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// A reference to the object representing the VPC&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// you want to deploy the instance into&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;vpc&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;defaultVpc&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ... more configuration&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import * as cdk from &amp;#x27;@aws-cdk/core&amp;#x27;import * as ec2 from &amp;#x27;@aws-cdk/aws-ec2&amp;#x27;export class MyAppStack extends cdk.Stack {  defaultVpc = ec2.Vpc.fromLookup(this, &amp;#x27;VPC&amp;#x27;, {    isDefault: true,  })  myVm = new ec2.Instance(this, &amp;#x27;myVm&amp;#x27;, {    // the type of instance to deploy (e.g. a &amp;#x27;t2.micro&amp;#x27;)    instanceType: new ec2.InstanceType(&amp;#x27;t2.micro&amp;#x27;),    // the id of the image to use for the instance    machineImage: someAmiId,    // A reference to the object representing the VPC    // you want to deploy the instance into    vpc: defaultVpc,    // ... more configuration  })}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;As you can see that there are 3 mandatory pieces of information we need to provide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href=&quot;https://aws.amazon.com/ec2/instance-types/&quot;&gt;type of EC2 instance&lt;/a&gt; we want to run (i.e. &lt;code&gt;t2.micro&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The id of the machine image (more on this in the next section)&lt;/li&gt;
&lt;li&gt;The id of the VPC (Virtual Private Cloud) where you want to deploy your instance. For example, in the snippet above, we are using the default VPC in your AWS account.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can also specify a ton of other optional configuration options (Security Groups, a role for IAM permissions, volumes, etc). For a full list of supported options you can check out &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.Instance.html&quot;&gt;the official documentation for the CDK EC2 Instance construct&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ok, now how do we specify that we want to use an Ubuntu-based image? Let’s talk about AMIs!&lt;/p&gt;
&lt;h2 id=&quot;ubuntu-amis-and-where-to-find-them&quot;&gt;Ubuntu AMIs and where to find them&lt;/h2&gt;
&lt;p&gt;When provisioning EC2 instances on AWS you have to provide a virtual machine image (an &lt;em&gt;AMI&lt;/em&gt; in AWS lingo). You can build and manage your own custom private images or use one of the many public images for different Linux distributions.&lt;/p&gt;
&lt;p&gt;These two approaches have their pros and cons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you use a public image, you will need to use an init script to provision the machine with all the needed software and configuration. This is a quick and easy way to experiment and iterate over different versions of your virtual machines. On the other hand, this approach might be slow, depending on how much stuff you need to do at every boot.&lt;/li&gt;
&lt;li&gt;If you build your own custom images you’ll need to have a pipeline (or some other reproducible approach) to bootstrap a base image, install all your software and create a new image from there. This path adds a bit more complexity but then your images will have everything built in and the bootstrap will probably be much faster.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this article we will go with a public image (Ubuntu) and we will provide the additional bits and pieces by using an init script.&lt;/p&gt;
&lt;p&gt;If you are interested in the “build your own image” approach, I’d recommend you to check out &lt;a href=&quot;https://aws.amazon.com/image-builder/&quot;&gt;EC2 Image Builder&lt;/a&gt; or &lt;a href=&quot;https://www.packer.io/&quot;&gt;Packer&lt;/a&gt; (a brilliant tool for building VM images from the same authors of Terraform).&lt;/p&gt;
&lt;p&gt;So, back to our main question: &lt;em&gt;how do we find a base image with Ubuntu installed&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;There’s an entire website dedicated to finding public AMIs for just Ubuntu: &lt;a href=&quot;https://cloud-images.ubuntu.com/locator/ec2/&quot;&gt;Ubuntu Amazon EC2 AMI Locator&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cloud-images.ubuntu.com/locator/ec2/&quot;&gt;&lt;img alt=&quot;Ubuntu Amazon EC2 AMI Locator screenshot&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;668&quot; src=&quot;https://loige.co/_astro/ubuntu-amazon-ec2-ami-finder-ui.BL0PrMeo_Zc6Hhb.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Every image is built for a specific AWS region, processor architecture, and instance type. Every image is identified by a unique ID called &lt;em&gt;AMI ID&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;When provisioning a new EC2 instance you need to specify the wanted &lt;em&gt;AMI ID&lt;/em&gt; and make sure to select the correct one for the region you are deploying your instance to.&lt;/p&gt;
&lt;p&gt;There are a couple of different ways to do that.&lt;/p&gt;
&lt;h3 id=&quot;machine-ami-map&quot;&gt;Machine AMI map&lt;/h3&gt;
&lt;p&gt;The simplest way to specify AMI IDs for all the regions we want to support is to use the &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.MachineImage.html#static-genericwbrlinuxamimap-props&quot;&gt;&lt;code&gt;ec2.MachineImage.genericLinux()&lt;/code&gt;&lt;/a&gt; helper function.&lt;/p&gt;
&lt;p&gt;This function accepts a map of AMI IDs where keys are regions and values are AMI IDs.&lt;/p&gt;
&lt;p&gt;Here’s an example:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;machineImage&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;MachineImage&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;genericLinux&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;eu-west-1&apos;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ami-0298c9e0d2c86b0ed&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;us-east-1&apos;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ami-019212a8baeffb0fa&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ap-east-1&apos;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ami-04c4bc345657bf245&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ... add all the regions you need to support&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const machineImage = ec2.MachineImage.genericLinux({  &amp;#x27;eu-west-1&amp;#x27;: &amp;#x27;ami-0298c9e0d2c86b0ed&amp;#x27;,  &amp;#x27;us-east-1&amp;#x27;: &amp;#x27;ami-019212a8baeffb0fa&amp;#x27;,  &amp;#x27;ap-east-1&amp;#x27;: &amp;#x27;ami-04c4bc345657bf245&amp;#x27;,  // ... add all the regions you need to support})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Here I have copied some AMI IDs manually from the Ubuntu Amazon EC2 AMI Locator website.&lt;/p&gt;
&lt;p&gt;This is a bit of tedious copy-paste ( 🍝 ) to do and you need to make sure you do it right. Furthermore, what if there’s an update? There will be new IDs and we will need to update them manually again… 🥲&lt;/p&gt;
&lt;p&gt;Of course, there’s an easier and more maintainable way! 😋&lt;/p&gt;
&lt;h3 id=&quot;machine-ami-from-a-public-ssm-parameter&quot;&gt;Machine AMI from a public SSM parameter&lt;/h3&gt;
&lt;p&gt;The better way is to use the function &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-ec2.MachineImage.html#static-fromwbrssmparameterparametername-os-userdata&quot;&gt;&lt;code&gt;ec2.MachineImage.fromSSMParameter()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As the name suggests, this function allows us to use take the AMI ID from an SSM parameter.
At a first glance, this idea might not sound particularly appealing. In fact, using SSM adds another layer of complexity. We would need to store the wanted AMI ID in SSM first somehow, only to consume the value later from our CDK stack.&lt;/p&gt;
&lt;p&gt;The good news is that there are some public SSM parameters that are already pre-populated with the latest ubuntu AMI IDs.&lt;/p&gt;
&lt;p&gt;Let’s try to run this in our terminal (you’ll need to have the &lt;a href=&quot;https://aws.amazon.com/cli/&quot;&gt;AWS CLI&lt;/a&gt; installed and configured):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;ssm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;get-parameter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;/aws/service/canonical/ubuntu/server/focal/stable/current/amd64/hvm/ebs-gp2/ami-id&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;aws ssm get-parameter --name &amp;#x22;/aws/service/canonical/ubuntu/server/focal/stable/current/amd64/hvm/ebs-gp2/ami-id&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The command above will output something like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;Parameter&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;Name&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;/aws/service/canonical/ubuntu/server/focal/stable/current/amd64/hvm/ebs-gp2/ami-id&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;Type&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;String&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;Value&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;ami-0298c9e0d2c86b0ed&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;Version&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;221&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;LastModifiedDate&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;2021-07-21T14:31:50.717000+01:00&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;ARN&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;arn:aws:ssm:eu-west-1::parameter/aws/service/canonical/ubuntu/server/focal/stable/current/amd64/hvm/ebs-gp2/ami-id&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;DataType&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;aws:ec2:image&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{  &amp;#x22;Parameter&amp;#x22;: {    &amp;#x22;Name&amp;#x22;: &amp;#x22;/aws/service/canonical/ubuntu/server/focal/stable/current/amd64/hvm/ebs-gp2/ami-id&amp;#x22;,    &amp;#x22;Type&amp;#x22;: &amp;#x22;String&amp;#x22;,    &amp;#x22;Value&amp;#x22;: &amp;#x22;ami-0298c9e0d2c86b0ed&amp;#x22;,    &amp;#x22;Version&amp;#x22;: 221,    &amp;#x22;LastModifiedDate&amp;#x22;: &amp;#x22;2021-07-21T14:31:50.717000+01:00&amp;#x22;,    &amp;#x22;ARN&amp;#x22;: &amp;#x22;arn:aws:ssm:eu-west-1::parameter/aws/service/canonical/ubuntu/server/focal/stable/current/amd64/hvm/ebs-gp2/ami-id&amp;#x22;,    &amp;#x22;DataType&amp;#x22;: &amp;#x22;aws:ec2:image&amp;#x22;  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;As the name of the SSM parameter suggests, these SSM parameters are managed directly by Canonical (the company behind Ubuntu). You can also see that there is a specific path structure to identify the AMI ID. If you are curious to find out more and to discover all the available images you can check out &lt;a href=&quot;https://discourse.ubuntu.com/t/finding-ubuntu-images-with-the-aws-ssm-parameter-store/15507&quot;&gt;Finding Ubuntu Images with the AWS SSM Parameter Store&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One more thing to notice is that SSM parameters are region-specific. You can have the same parameter key in different regions and therefore have different values in different regions (given the same key).&lt;/p&gt;
&lt;p&gt;I am running this command using &lt;code&gt;eu-west-1&lt;/code&gt; as the default region and you can see that the &lt;code&gt;Value&lt;/code&gt; matches the AMI ID we have manually specified with the AMI map approach. Try to switch your region using the &lt;code&gt;--region&lt;/code&gt; flag and you will get the correct AMI ID for the given region.&lt;/p&gt;
&lt;p&gt;This is a rather clever usage of SSM if you ask me! 🤩&lt;/p&gt;
&lt;p&gt;Enough chit chat, let’s see how to use this approach with CDK:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;machineImage&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;MachineImage&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fromSSMParameter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/aws/service/canonical/ubuntu/server/focal/stable/current/amd64/hvm/ebs-gp2/ami-id&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;OperatingSystemType&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;LINUX&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const machineImage = ec2.MachineImage.fromSSMParameter(  &amp;#x27;/aws/service/canonical/ubuntu/server/focal/stable/current/amd64/hvm/ebs-gp2/ami-id&amp;#x27;,  ec2.OperatingSystemType.LINUX,)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That’s it! Now we can pass the &lt;code&gt;machineImage&lt;/code&gt; value to the settings of our EC2 instance!&lt;/p&gt;
&lt;h2 id=&quot;a-simple-ec2-instance-with-ubuntu&quot;&gt;A simple EC2 instance with Ubuntu&lt;/h2&gt;
&lt;p&gt;Ok, now we have all the building blocks to provision the most basic Ubuntu-based EC2 instance.&lt;/p&gt;
&lt;p&gt;This is how the code for our stack (&lt;code&gt;lib/*stack.ts&lt;/code&gt;) looks like so far:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/core&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;@aws-cdk/aws-ec2&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;CdkUbuntuEc2Stack&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Stack&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;constructor&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;scope&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Construct&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;props&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#387138&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;StackProps&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;super&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;scope&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;account&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;CDK_DEPLOY_ACCOUNT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;CDK_DEFAULT_ACCOUNT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;region&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;CDK_DEPLOY_REGION&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;CDK_DEFAULT_REGION&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;defaultVpc&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Vpc&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fromLookup&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;VPC&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;isDefault&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;machineImage&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;MachineImage&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fromSSMParameter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/aws/service/canonical/ubuntu/server/focal/stable/current/amd64/hvm/ebs-gp2/ami-id&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;OperatingSystemType&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;LINUX&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;myVm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Instance&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;myVm&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;instanceType&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;InstanceType&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;t2.micro&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;machineImage&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;machineImage&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;vpc&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;defaultVpc&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import * as cdk from &amp;#x27;@aws-cdk/core&amp;#x27;import * as ec2 from &amp;#x27;@aws-cdk/aws-ec2&amp;#x27;export class CdkUbuntuEc2Stack extends cdk.Stack {  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {    super(scope, id, {      env: {        account:          process.env.CDK_DEPLOY_ACCOUNT || process.env.CDK_DEFAULT_ACCOUNT,        region: process.env.CDK_DEPLOY_REGION || process.env.CDK_DEFAULT_REGION,      },      ...props,    })    const defaultVpc = ec2.Vpc.fromLookup(this, &amp;#x27;VPC&amp;#x27;, {      isDefault: true,    })    const machineImage = ec2.MachineImage.fromSSMParameter(      &amp;#x27;/aws/service/canonical/ubuntu/server/focal/stable/current/amd64/hvm/ebs-gp2/ami-id&amp;#x27;,      ec2.OperatingSystemType.LINUX,    )    const myVm = new ec2.Instance(this, &amp;#x27;myVm&amp;#x27;, {      instanceType: new ec2.InstanceType(&amp;#x27;t2.micro&amp;#x27;),      machineImage: machineImage,      vpc: defaultVpc,    })  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If we try to run &lt;code&gt;cdk deploy&lt;/code&gt; we should see something like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The preview of what will be deployed by running cdk deploy&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;473&quot; src=&quot;https://loige.co/_astro/cdk-deploy-prompt-example.BxrlC9sh_1gstOs.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;We can now say &lt;code&gt;y&lt;/code&gt; to confirm the deployment and sit patiently with our fingers crossed… 🤞&lt;/p&gt;
&lt;p&gt;Ok … ⏱ wait over!&lt;/p&gt;
&lt;p&gt;If all went well, we should see something like this in the console:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;✅  CdkUbuntuEc2Stack&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Stack ARN:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;arn:aws:cloudformation:eu-west-1:012345678901:stack/CdkUbuntuEc2Stack/a0d34481-a364-4261-864b-3cb16f57dc15&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot; ✅  CdkUbuntuEc2StackStack ARN:arn:aws:cloudformation:eu-west-1:012345678901:stack/CdkUbuntuEc2Stack/a0d34481-a364-4261-864b-3cb16f57dc15&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Our machine is deployed! 🎉&lt;/p&gt;
&lt;p&gt;As a small aside, I have to say that &lt;a href=&quot;/random-emoji-in-your-prompt-how-and-why&quot;&gt;I love the usage of some good emojis in the terminal&lt;/a&gt;, well-done AWS!&lt;/p&gt;
&lt;p&gt;But let’s be fair, our virtual machine is not very useful… it doesn’t do anything right now!&lt;/p&gt;
&lt;p&gt;Let’s try to update our machine and make it do something useful. For instance, we could install nginx and enable ingress on port 80 so that, once the machine is provisioned, we will be able to see the default nginx welcome page.&lt;/p&gt;
&lt;p&gt;In a real-life scenario, you might do something a bit more sophisticated to deploy and run a real application on the machine.&lt;/p&gt;
&lt;h3 id=&quot;adding-a-security-group-to-an-ec2-with-cdk&quot;&gt;Adding a security group to an EC2 with CDK&lt;/h3&gt;
&lt;p&gt;Let’s start by adding a security group to our EC2, this is something we can do by adding the following code to our stack:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;myVmSecurityGroup&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;SecurityGroup&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;myVmSecurityGroup&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;vpc&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;defaultVpc&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;myVmSecurityGroup&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;addIngressRule&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Peer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;anyIpv4&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Port&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;tcp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;80&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;httpIpv4&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;myVmSecurityGroup&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;addIngressRule&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Peer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;anyIpv6&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Port&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;tcp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;80&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;httpIpv6&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const myVmSecurityGroup = new ec2.SecurityGroup(this, &amp;#x27;myVmSecurityGroup&amp;#x27;, {  vpc: defaultVpc,})myVmSecurityGroup.addIngressRule(  ec2.Peer.anyIpv4(),  ec2.Port.tcp(80),  &amp;#x27;httpIpv4&amp;#x27;,)myVmSecurityGroup.addIngressRule(  ec2.Peer.anyIpv6(),  ec2.Port.tcp(80),  &amp;#x27;httpIpv6&amp;#x27;,)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Then we need to associate this new security group to the instance by setting the &lt;code&gt;securityGroup&lt;/code&gt; property:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;myVm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Instance&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;myVm&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;securityGroup&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;myVmSecurityGroup&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const myVm = new ec2.Instance(this, &amp;#x27;myVm&amp;#x27;, {  // ...  securityGroup: myVmSecurityGroup,  // ...})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Ok, now our virtual machine will be able to accept ingress traffic on port &lt;code&gt;80&lt;/code&gt; from all IPv4 and IPv6 addresses.&lt;/p&gt;
&lt;h3 id=&quot;installing-software-by-using-cloudformation-init-with-cdk&quot;&gt;Installing software by using CloudFormation init with CDK&lt;/h3&gt;
&lt;p&gt;CloudFormation supports &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-init.html&quot;&gt;a way to execute init scripts once a machine boots&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;CDK supports this feature as well and we can use it with the &lt;code&gt;init&lt;/code&gt; configuration option in our VM definition:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;myVm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Instance&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;myVm&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;init&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;CloudFormationInit&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fromElements&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;InitCommand&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;shellCommand&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;sudo apt-get update -y&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;InitCommand&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;shellCommand&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;sudo apt-get install -y nginx&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ... more configuration&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const myVm = new ec2.Instance(this, &amp;#x27;myVm&amp;#x27;, {  // ...  init: ec2.CloudFormationInit.fromElements(    ec2.InitCommand.shellCommand(&amp;#x27;sudo apt-get update -y&amp;#x27;),    ec2.InitCommand.shellCommand(&amp;#x27;sudo apt-get install -y nginx&amp;#x27;),  ),  // ... more configuration})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h3 id=&quot;cdk-signal-problems-with-ubuntu&quot;&gt;CDK signal problems with Ubuntu&lt;/h3&gt;
&lt;p&gt;At this point we are ready to do another deployment, so let’s run &lt;code&gt;cdk deploy&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This time the deployment should take a long time (10-15mins) and then fail with an error that should look like the following:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;CdkUbuntuEc2Stack: deploying...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;CdkUbuntuEc2Stack: creating CloudFormation changeset...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;17:28:01 | UPDATE_FAILED        | AWS::EC2::Instance        | myVm11CC711A&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Failed to receive 1 resource signal(s) within the specified duration&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;CdkUbuntuEc2Stack: deploying...CdkUbuntuEc2Stack: creating CloudFormation changeset...17:28:01 | UPDATE_FAILED        | AWS::EC2::Instance        | myVm11CC711AFailed to receive 1 resource signal(s) within the specified duration&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;It took me a while to figure out what was going wrong and how to solve this problem.&lt;/p&gt;
&lt;p&gt;One thing that I eventually did during my investigation was to run &lt;code&gt;cdk synth&lt;/code&gt; to see the CloudFormation stack that was being generated and deployed by CDK.&lt;/p&gt;
&lt;p&gt;In there I noticed that as part of the &lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html&quot;&gt;user data script&lt;/a&gt;, the following command gets executed: &lt;code&gt;/opt/aws/bin/cfn-signal&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, with a bit of timed effort, I managed to establish an SSH connection to an instance while it was being provisioned (and before it was destroyed by CDK) and I realized that the default Ubuntu distribution does not have &lt;code&gt;cfn-signal&lt;/code&gt; installed.&lt;/p&gt;
&lt;p&gt;This makes sense. This is a specific AWS utility that is pre-installed in Amazon Linux, but there is no reason why it should be installed in Ubuntu or other generic Linux distributions.&lt;/p&gt;
&lt;p&gt;So now the problem is “How do we install cfn-signal?”&lt;/p&gt;
&lt;p&gt;The answer to this question is “by using a custom user data script”!&lt;/p&gt;
&lt;h2 id=&quot;installing-aws-linux-utilities-on-an-ubuntu-image-using-cdk&quot;&gt;Installing AWS Linux utilities on an Ubuntu Image using CDK&lt;/h2&gt;
&lt;p&gt;We can install &lt;code&gt;cfn-signal&lt;/code&gt; and other AWS Linux utilities in our virtual machine by creating a custom user data script.&lt;/p&gt;
&lt;p&gt;User data scripts run before the init step is executed, so by doing this we should be able to fix our current issue.&lt;/p&gt;
&lt;p&gt;After some research and by putting together different resources I managed to get a working script to install the &lt;a href=&quot;https://github.com/aws-quickstart/quickstart-linux-utilities&quot;&gt;AWS Linux utilities&lt;/a&gt; on Ubuntu:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;#/usr/bin/env bash&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;apt-get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-y&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;apt-get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;install&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-y&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;awscli&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;ec2-instance-connect&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;u&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;ntil&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;clone&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;https://github.com/aws-quickstart/quickstart-linux-utilities.git&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;do&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Retrying&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;done&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/quickstart-linux-utilities&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;source&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;quickstart-cfn-tools.source&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;qs_update-os&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; || &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;qs_err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;qs_bootstrap_pip&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; || &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;qs_err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;qs_aws-cfn-bootstrap&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; || &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;qs_err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-p&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/opt/aws/bin&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/usr/local/bin/cfn-&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/opt/aws/bin/&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;apt-get update -y;apt-get install -y git awscli ec2-instance-connect;until git clone https://github.com/aws-quickstart/quickstart-linux-utilities.git; do echo &amp;#x22;Retrying&amp;#x22;; done;cd /quickstart-linux-utilities;source quickstart-cfn-tools.source;qs_update-os || qs_err;qs_bootstrap_pip || qs_err;qs_aws-cfn-bootstrap || qs_err;mkdir -p /opt/aws/bin;ln -s /usr/local/bin/cfn-* /opt/aws/bin/;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note that this script also installs the AWS CLI and &lt;code&gt;ec2-instance-connect&lt;/code&gt;. These are not strictly necessary for our use case, but they are nice to have.&lt;/p&gt;
&lt;p&gt;In CDK, we can create a user data script with these commands as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;userData&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;UserData&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;forLinux&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;userData&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;addCommands&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;apt-get update -y&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;apt-get install -y git awscli ec2-instance-connect&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;until git clone https://github.com/aws-quickstart/quickstart-linux-utilities.git; do echo &quot;Retrying&quot;; done&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;cd /quickstart-linux-utilities&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;source quickstart-cfn-tools.source&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;qs_update-os || qs_err&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;qs_bootstrap_pip || qs_err&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;qs_aws-cfn-bootstrap || qs_err&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;mkdir -p /opt/aws/bin&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;ln -s /usr/local/bin/cfn-* /opt/aws/bin/&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const userData = ec2.UserData.forLinux()userData.addCommands(  &amp;#x27;apt-get update -y&amp;#x27;,  &amp;#x27;apt-get install -y git awscli ec2-instance-connect&amp;#x27;,  &amp;#x27;until git clone https://github.com/aws-quickstart/quickstart-linux-utilities.git; do echo &amp;#x22;Retrying&amp;#x22;; done&amp;#x27;,  &amp;#x27;cd /quickstart-linux-utilities&amp;#x27;,  &amp;#x27;source quickstart-cfn-tools.source&amp;#x27;,  &amp;#x27;qs_update-os || qs_err&amp;#x27;,  &amp;#x27;qs_bootstrap_pip || qs_err&amp;#x27;,  &amp;#x27;qs_aws-cfn-bootstrap || qs_err&amp;#x27;,  &amp;#x27;mkdir -p /opt/aws/bin&amp;#x27;,  &amp;#x27;ln -s /usr/local/bin/cfn-* /opt/aws/bin/&amp;#x27;,)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Then, &lt;code&gt;userData&lt;/code&gt; needs to be passed to our &lt;code&gt;machineImage&lt;/code&gt; as the third argument:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;machineImage&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;MachineImage&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fromSSMParameter&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/aws/service/canonical/ubuntu/server/focal/stable/current/amd64/hvm/ebs-gp2/ami-id&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;ec2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;OperatingSystemType&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;LINUX&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;userData&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const machineImage = ec2.MachineImage.fromSSMParameter(  &amp;#x27;/aws/service/canonical/ubuntu/server/focal/stable/current/amd64/hvm/ebs-gp2/ami-id&amp;#x27;,  ec2.OperatingSystemType.LINUX,  userData,)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;With these changes, we should be able to get everything working, but before doing that let’s do one last change: let’s add an output parameter so that, once our stack is deployed, we can see the URL to our web server running nginx.&lt;/p&gt;
&lt;h3 id=&quot;adding-an-output-value-in-cdk&quot;&gt;Adding an output value in CDK&lt;/h3&gt;
&lt;p&gt;Adding an output value is quite simple with CDK, we just need to instantiate a new &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.CfnOutput.html&quot;&gt;&lt;code&gt;cdk.CfnOutput&lt;/code&gt;&lt;/a&gt; object:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;webVmUrl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;CfnOutput&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;webVmUrl&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`http://&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;myVm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#387138&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;instancePublicIp&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/`&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;The URL of our instance&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;exportName&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;webVmUrl&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const webVmUrl = new cdk.CfnOutput(this, &amp;#x27;webVmUrl&amp;#x27;, {  value: &amp;#x60;http://${myVm.instancePublicIp}/&amp;#x60;,  description: &amp;#x27;The URL of our instance&amp;#x27;,  exportName: &amp;#x27;webVmUrl&amp;#x27;,})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now if we run &lt;code&gt;cdk deploy&lt;/code&gt;, after a few minutes we should see an output like the following:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;✅  CdkUbuntuEc2Stack&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Outputs:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;CdkUbuntuEc2Stack.webVmUrl = http://54.154.84.11/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Stack ARN:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;arn:aws:cloudformation:eu-west-1:012345678901:stack/CdkUbuntuEc2Stack/22c0faa4-adb4-4724-a4c4-c8ea21b7ac07&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot; ✅  CdkUbuntuEc2StackOutputs:CdkUbuntuEc2Stack.webVmUrl = http://54.154.84.11/Stack ARN:arn:aws:cloudformation:eu-west-1:012345678901:stack/CdkUbuntuEc2Stack/22c0faa4-adb4-4724-a4c4-c8ea21b7ac07&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If we visit the URL in the output parameter we should see the default nginx welcome page:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;nginx default welcome page running on an Ubuntu-based EC2 on AWS&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;505&quot; src=&quot;https://loige.co/_astro/welcome-to-nginx-screenshot.HTKzQ7IZ_ZON7lQ.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;It’s working, we made it! 🥳&lt;/p&gt;
&lt;p&gt;If you want to see how the full code looks like you can check out the &lt;a href=&quot;https://github.com/lmammino/cdk-ubuntu-ec2&quot;&gt;“official” repository for this project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to clean up your account and destroy the stack created by this project, you can run:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;cdk&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;destroy&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;cdk destroy&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article we learned how to use CDK to provision an Ubuntu-based virtual machine and how to configure it to run the default installation of nginx.&lt;/p&gt;
&lt;p&gt;In the process we also learned a bunch of related concepts such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;what is CDK&lt;/li&gt;
&lt;li&gt;how to use it to define an EC2 instance&lt;/li&gt;
&lt;li&gt;how to reference an AMI&lt;/li&gt;
&lt;li&gt;how to add security groups&lt;/li&gt;
&lt;li&gt;how to use user data and init script&lt;/li&gt;
&lt;li&gt;how to install the AWS Linux Utilities&lt;/li&gt;
&lt;li&gt;…and finally how to create a CDK output argument.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;WOW that was quite a journey, and there I thought this would be a short article! 😅&lt;/p&gt;
&lt;p&gt;I hope I didn’t bore you to death and that this article was somewhat useful! &lt;a href=&quot;#comments&quot;&gt;Let me know what you think in the comments&lt;/a&gt; and feel free to &lt;a href=&quot;https://twitter.com/loige&quot;&gt;connect with me on Twitter&lt;/a&gt; for more &lt;a href=&quot;/tag/aws&quot;&gt;AWS&lt;/a&gt; and cloud chats.&lt;/p&gt;
&lt;p&gt;If you are interested in working more with AWS and the cloud, you might also want to check out &lt;a href=&quot;https://www.fourtheorem.com/&quot;&gt;fourTheorem&lt;/a&gt;, a group of business focused technologists that &lt;a href=&quot;https://www.fourtheorem.com/case-studies&quot;&gt;has already helped many companies&lt;/a&gt; to get the best out of the cloud (yes, this is where I work 🙃).&lt;/p&gt;
&lt;p&gt;See you in the next post!&lt;/p&gt;
&lt;p&gt;Bye 👋&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Thanks to &lt;a href=&quot;https://twitter.com/eoins&quot;&gt;Eoin Shanaghy&lt;/a&gt; for kindly reviewing this article!&lt;/small&gt;&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/provision-ubuntu-ec2-with-cdk.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/provision-ubuntu-ec2-with-cdk.png" width="1200" height="630"/></media:content><category>aws</category><category>cdk</category><category>javascript</category><category>typescript</category><category>nginx</category><author>Luciano Mammino</author><comments>https://loige.co/provision-ubuntu-ec2-with-cdk/#comments</comments><enclosure url="https://loige.co/og/provision-ubuntu-ec2-with-cdk.png" length="0" type="image/png"/></item><item><title>Learning Rust through open source and live code reviews</title><link>https://loige.co/learning-rust-through-open-source-and-live-code-reviews/</link><guid isPermaLink="true">https://loige.co/learning-rust-through-open-source-and-live-code-reviews/</guid><description>This article summarizes the experience of two developers learning Rust by building an open source project and having it reviewed live by a Rust expert. It covers the improvements suggested during the review, including simplifying project structure, adding documentation, handling strings, removing code duplication, improving input validation and testing.</description><pubDate>Sun, 11 Oct 2020 19:50:00 GMT</pubDate><content:encoded>&lt;p&gt;Hello from Luciano and Stefano! 👋&lt;/p&gt;
&lt;p&gt;In the last few years we set ourselves onto the Rust learning path. We don’t work with Rust during our daily jobs and we come to be interested in the language for different reasons (more on this later), so we decided to take it easy and invest some of our free time reading books and tutorials, watching videos about Rust and doing occasional coding challenges. Finally after about one year of sporadic studying sessions we felt ready to attempt our first open source Rust project: &lt;a href=&quot;https://github.com/lmammino/jwtinfo&quot;&gt;&lt;code&gt;jwtinfo&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We recently had the pleasure to have our crate reviewed by &lt;a href=&quot;https://twitter.com/timClicks&quot;&gt;Tim McNamara&lt;/a&gt; of &lt;a href=&quot;https://www.manning.com/books/rust-in-action&quot;&gt;Rust in Action&lt;/a&gt;’s fame (one the best Rust books out there in our honest opinion!). The review was carried out live on &lt;a href=&quot;https://www.twitch.tv/timclicks&quot;&gt;Tim’s twitch channel&lt;/a&gt; and it gave us a lot of cues on things to improve.
This article serves as a summary for our experience and memorandum of all the interesting things we learned. If you are learning Rust as well, we hope you will find some of these notes useful!&lt;/p&gt;
&lt;h2 id=&quot;our-motivation&quot;&gt;Our motivation&lt;/h2&gt;
&lt;p&gt;Before getting into the weeds of what we learned, it probably makes sense for us to give you a little intro on who we are and why we are interested in Rust. If you couldn’t care less about who is writing this, just skip to the next section! 😜&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/loige&quot;&gt;Luciano&lt;/a&gt;, considers himself a fullstack cloud developer. His career has been gravitating mostly around building web and cloud-focused products. He has been using mainly high level languages throughout his career (qBasic/VB, Php, JavaScript, Python, Go, Node.js). Node.js is his tool of choice and he is one of the co-authors of the book &lt;a href=&quot;https://www.nodejsdesignpatterns.com/&quot;&gt;Node.js Design Patterns (Packt)&lt;/a&gt;. He is fascinated by Rust because it unveils fundamental topics like memory management and safety which he doesn’t know much about, but he is also interested in using Rust on the web building Rust web servers and frontends with WebAssembly. If you are curious to know more about Luciano, check out the &lt;a href=&quot;/about&quot;&gt;about section of this blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/StefanoAbalsamo&quot;&gt;Stefano&lt;/a&gt; is a long time low-level C/C++ developer who got close to the world of web development in the last few years. Based on his previous experience, Stefano saw in Rust a great potential to write safe and performant code across all the stack.&lt;/p&gt;
&lt;h2 id=&quot;the-project-and-a-quick-jwt-primer&quot;&gt;The project and a quick JWT primer&lt;/h2&gt;
&lt;p&gt;Just to give you a little bit of context on the project, &lt;code&gt;jwtinfo&lt;/code&gt; is a simple command line application (and a library) that allows you to validate and decode a JWTs (JSON Web Tokens) and visualize the content of the “body” (or “payload”) section of the token. If you are not familiar with what JWT is, you can read this 5-minutes article called &lt;a href=&quot;https://loige.co/whats-in-a-jwt&quot;&gt;what’s in a JWT&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;jwtinfo&lt;/code&gt; is a command line utility that allows you to see what’s inside a JWT. For instance you can run it like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;jwtinfo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;jwtinfo eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And it will print:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;sub&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;1234567890&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;John Doe&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;iat&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1516239022&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{ &amp;#x22;sub&amp;#x22;: &amp;#x22;1234567890&amp;#x22;, &amp;#x22;name&amp;#x22;: &amp;#x22;John Doe&amp;#x22;, &amp;#x22;iat&amp;#x22;: 1516239022 }&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Which is essentially the &lt;em&gt;body&lt;/em&gt; (or &lt;em&gt;payload&lt;/em&gt;) of the token we pass as input to &lt;code&gt;jwtinfo&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Of course, &lt;code&gt;jwtinfo&lt;/code&gt; will also tell you if you try to pass a token that is not valid and can’t be parsed correctly, so, in a way, you could also call it a JWT validator, even though, at this time, it does not offer any functionality to validate the token signature against a secret or a public key.&lt;/p&gt;
&lt;h2 id=&quot;the-review&quot;&gt;The review&lt;/h2&gt;
&lt;p&gt;The idea of the code review came up when Tim &lt;a href=&quot;https://twitter.com/timClicks/status/1306105789245841409&quot;&gt;asked on Twitter what people would be interested to see in a Rust live stream&lt;/a&gt;. Luciano took this opportunity to suggest to do some live code review of Rust beginners’ crates. Tim seemed to like the idea and of course at that point we had to volunteer our project 😇&lt;/p&gt;
&lt;p&gt;After a couple of weeks Tim proceeded with the live review &lt;a href=&quot;https://www.youtube.com/watch?v=1JZ1oWp3PuA&quot;&gt;that you can now watch on YouTube&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Tim McNamara (timclicks) reviewing the jwtinfo Rust crate on Twitch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;561&quot; src=&quot;https://loige.co/_astro/timclicks-reviewing-jwtinfo-rust-crate-on-twitch.CHKXe7z-_Z1HbzQv.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/loige/status/1306227257606836227&quot;&gt;Our ask&lt;/a&gt; was to get some generic advice around the following topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Project structure&lt;/li&gt;
&lt;li&gt;Error management&lt;/li&gt;
&lt;li&gt;Enums&lt;/li&gt;
&lt;li&gt;Exposing a lib and a cli together&lt;/li&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;li&gt;Build process&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In hindsight, we reckon that this list might look a bit random and unclear, but nonetheless Tim managed to address most of these points and provided great insights around the concerns we had around these topics.&lt;/p&gt;
&lt;p&gt;We are going now to showcase our notes, in no special order and try to provide as much context as possible based on what we learned during the review process and even after it when we decided to go in greater depth on some of the suggested improvements.&lt;/p&gt;
&lt;h2 id=&quot;simplified-project-structure-and-exposing-a-cli-and-a-library&quot;&gt;Simplified project structure and exposing a CLI and a library&lt;/h2&gt;
&lt;p&gt;When we started working on this project we just wanted to create a simple command line tool. As we were writing the code, we realized that all the JWT parsing and validation logic could be externalized to its own external module. We didn’t really want to split the project in two, mostly for simplicity, but also because there are &lt;a href=&quot;https://crates.io/search?q=jwt&quot;&gt;many cool JWT crates&lt;/a&gt; out there and don’t want to compete or even try to provide feature parity with them. This is a learning project, and as such, we thought it might be nice to expose our JWT parsing layer as a library too.
Tim provided 2 interesting pieces of advice. The first one is to simplify the folder structure. It turns out we were following a pattern that was required in Rust 2015 edition, which looks like the following:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;src/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;├── main.rs # our CLI app&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;└── jwt # our internal lib for JWT parsing&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;├── mod.rs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;└── test.rs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;src/├── main.rs # our CLI app└── jwt # our internal lib for JWT parsing    ├── mod.rs    └── test.rs&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In Rust 2018 edition it is possible to avoid creating &lt;code&gt;mod.rs&lt;/code&gt; files. But why would you want to avoid them in the first place? It turns out that those files tend to be quite anonymous in big projects. If you have many submodules, chances are that you will end up having many tabs open at a given point in time and they would all be saying &lt;code&gt;mod.rs&lt;/code&gt;. It will probably take you a while to be able to navigate through them and find the file you were looking for. What we learned is that with Rust 2018 we could simply promote &lt;code&gt;src/jwt/mod.rs&lt;/code&gt; to &lt;code&gt;src/jwt.rs&lt;/code&gt;. No other code change required: all the imports still work as a charm! So now our code structure looks like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;src/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;├── main.rs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;├── jwt.rs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;└── jwt/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;└── test.rs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;src/├── main.rs├── jwt.rs└── jwt/    └── test.rs&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This seems much better, we like flatter structures and descriptive file names! If you are curious to find out more about this there is an official piece of documentation recommending &lt;a href=&quot;https://doc.rust-lang.org/stable/edition-guide/rust-2018/module-system/path-clarity.html#no-more-modrs&quot;&gt;no more &lt;code&gt;mod.rs&lt;/code&gt;&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;In order to expose the &lt;code&gt;jwt.rs&lt;/code&gt; module as part of the public library we finally had to do a couple of minor changes in our &lt;code&gt;cargo.toml&lt;/code&gt; and in our &lt;code&gt;main.rs&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Our &lt;code&gt;cargo.toml&lt;/code&gt; needed to have new sections indicating how to compile the project for the different targets (CLI application and library). We achieved that by adding the following lines:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;toml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#3360C1&quot;&gt;lib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;jwtinfo&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;src/main.rs&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[[&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#3360C1&quot;&gt;bin&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;jwtinfo&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;src/main.rs&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;[lib]name = &amp;#x22;jwtinfo&amp;#x22;path = &amp;#x22;src/main.rs&amp;#x22;[[bin]]name = &amp;#x22;jwtinfo&amp;#x22;path = &amp;#x22;src/main.rs&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If you are wondering why &lt;code&gt;lib&lt;/code&gt; comes with only one pair of square brackets while &lt;code&gt;bin&lt;/code&gt; comes with two, well we had the same question too! We found an answer in the &lt;a href=&quot;https://doc.rust-lang.org/cargo/reference/cargo-targets.html#configuring-a-target&quot;&gt;official cargo documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The double-bracket sections like &lt;code&gt;[[bin]]&lt;/code&gt; are array-of-table of TOML, which means you can write more than one &lt;code&gt;[[bin]]&lt;/code&gt; section to make several executables in your crate. You can only specify one library, so &lt;code&gt;[lib]&lt;/code&gt; is a normal TOML table.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once we applied these changes, everything seemed to work great. Except, when we published the changes on GitHub we started to our CI being polluted by the following warning:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“file found to be present in multiple build targets”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img alt=&quot;File found to be present in multiple build targets - screenshot from GitHub Actions&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1040&quot; height=&quot;211&quot; src=&quot;https://loige.co/_astro/file-found-to-be-present-in-multiple-build-targets.CXuUSVWa_2bFP6S.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Once again, we had to roll up our sleeves and try to figure out what this actually meant. We found the answer in a &lt;a href=&quot;https://github.com/rust-lang/cargo/issues/5930&quot;&gt;Cargo issue&lt;/a&gt; where Alex Chricton suggested the &lt;a href=&quot;https://github.com/rust-lang/cargo/issues/5930#issuecomment-449425113&quot;&gt;following solution&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[…] we’d recommend either using a library or a &lt;code&gt;mod foo&lt;/code&gt; pointing to the same location. If you use a shared library crate then you’ll get better compile times though!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, finally we managed to resolve this issue by moving all our CLI logic into a dedicated &lt;code&gt;cli.rs&lt;/code&gt; file and changed the content of the original &lt;code&gt;main.rs&lt;/code&gt; into this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;mod&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; jwt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;#[macro_use]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;extern&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;crate&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; lazy_static;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;pub mod jwt;#[macro_use]extern crate lazy_static;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note how we also marked the &lt;code&gt;jwt&lt;/code&gt; sub-module as public, so that it is actually accessible to whoever is using the library.&lt;/p&gt;
&lt;p&gt;Finally our &lt;code&gt;cargo.toml&lt;/code&gt;, now looks like the following:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;toml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#3360C1&quot;&gt;lib&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;jwtinfo&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;src/main.rs&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[[&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#3360C1&quot;&gt;bin&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;jwtinfo&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;src/cli.rs&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;[lib]name = &amp;#x22;jwtinfo&amp;#x22;path = &amp;#x22;src/main.rs&amp;#x22;[[bin]]name = &amp;#x22;jwtinfo&amp;#x22;path = &amp;#x22;src/cli.rs&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And our files structure looks like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;src/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;├── cli.rs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;├── jwt.rs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;├── main.rs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;└── jwt/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;└── test.rs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;src/├── cli.rs├── jwt.rs├── main.rs└── jwt/    └── test.rs&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And that annoying warning disappeared. Plus, we are probably getting slightly faster compile times now! ⚡️&lt;/p&gt;
&lt;h2 id=&quot;document-all-the-things&quot;&gt;Document all the things&lt;/h2&gt;
&lt;p&gt;One thing that we completely neglected so far was documentation. Rust has an amazing built-in utility to be able to document the API of crates and even to publish them online.
There is even an official piece of documentation that gives guidance on how to write &lt;a href=&quot;https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#making-useful-documentation-comments&quot;&gt;useful documentation comments&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you just want to get started with writing docs for your crates, probably the easiest thing to do is to check out the &lt;a href=&quot;https://doc.rust-lang.org/stable/rust-by-example/meta/doc.html&quot;&gt;“Rust by example” page about documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As you start adding documentation comments to your crate, you can simply run &lt;code&gt;cargo doc --open&lt;/code&gt; to compile the website with the documentation locally and open it with your browser. This is extremely convenient to make sure that, once you publish the crate, the documentation online will look as expected.&lt;/p&gt;
&lt;p&gt;Few days after the review we rolled up our sleeves and started to document our library. If you are curious to see what it took to go from 0 to 100, this is our PR that added documentation to the crate: &lt;a href=&quot;https://github.com/lmammino/jwtinfo/pull/22&quot;&gt;lmammino/jwtinfo/pull/22&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One of the most amazing thing was that, once we published a new version of the crate on crates.io, after few minutes we could navigate our crate doc online at &lt;a href=&quot;https://docs.rs/jwtinfo&quot;&gt;docs.rs/jwtinfo&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;jwtinfo Rust docs page screenshot from the rendered docs in the browser&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;945&quot; height=&quot;862&quot; src=&quot;https://loige.co/_astro/jwtinfo-rust-docs-page.zAbmWc68_ZeVyia.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Another thing that we loved about writing documentation in Rust is the ability to execute code examples to make sure they are actually correct.
Just to show a real example, this is a piece of documentation in our crate:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//! To parse a given JWT as a string:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//! ```rust&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//! use jwtinfo::{jwt};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//! let token_str = &quot;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c&quot;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//! match jwt::parse(token_str) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//!   Ok(token) =&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//!     // do something with token&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//!     assert_eq!(token.header.to_string(), &quot;{\&quot;alg\&quot;:\&quot;HS256\&quot;,\&quot;typ\&quot;:\&quot;JWT\&quot;}&quot;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//!     assert_eq!(token.body.to_string(), &quot;{\&quot;iat\&quot;:1516239022,\&quot;name\&quot;:\&quot;John Doe\&quot;,\&quot;sub\&quot;:\&quot;1234567890\&quot;}&quot;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//!   }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//!   Err(e) =&gt; panic!(e)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//! }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//! ```&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;//! To parse a given JWT as a string://!//! &amp;#x60;&amp;#x60;&amp;#x60;rust//! use jwtinfo::{jwt};//!//! let token_str = &amp;#x22;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c&amp;#x22;;//! match jwt::parse(token_str) {//!   Ok(token) =&gt; {//!     // do something with token//!     assert_eq!(token.header.to_string(), &amp;#x22;{\&amp;#x22;alg\&amp;#x22;:\&amp;#x22;HS256\&amp;#x22;,\&amp;#x22;typ\&amp;#x22;:\&amp;#x22;JWT\&amp;#x22;}&amp;#x22;);//!     assert_eq!(token.body.to_string(), &amp;#x22;{\&amp;#x22;iat\&amp;#x22;:1516239022,\&amp;#x22;name\&amp;#x22;:\&amp;#x22;John Doe\&amp;#x22;,\&amp;#x22;sub\&amp;#x22;:\&amp;#x22;1234567890\&amp;#x22;}&amp;#x22;);//!   }//!   Err(e) =&gt; panic!(e)//! }//! &amp;#x60;&amp;#x60;&amp;#x60;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;When we run our test suite with &lt;code&gt;cargo test&lt;/code&gt;, Cargo will also extrapolate this example here from the docs and execute it. This will help us make sure that our documentation is actually correct and that it doesn’t go stale over time.&lt;/p&gt;
&lt;p&gt;If you have a big test suite and you just want to run your doc tests you can simply do that with &lt;code&gt;cargo test --doc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Running docs tests with rust test --doc&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1032&quot; height=&quot;382&quot; src=&quot;https://loige.co/_astro/jwtinfo-running-docs-test-with-rust-docs.hcd-bRTW_J4A8V.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Finally, another small trick we discovered is that you can hide specific functions or types from the generated documentation (in case those are private details you don’t want to expose to the crate users). Hiding documentation members is as simple as adding the following annotation:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;#[doc(hidden)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;#[doc(hidden)]&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;For instance, in our crate we have:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;#[doc(hidden)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;parse_base64_string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;JWTParseError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;base64&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;decode_config&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, *&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;BASE64_CONFIG&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)?;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;from_utf8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)?;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Ok&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;to_string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;#[doc(hidden)]fn parse_base64_string(s: &amp;#x26;str) -&gt; Result&lt;String, JWTParseError&gt; {    let s = base64::decode_config(s, *BASE64_CONFIG)?;    let s = str::from_utf8(&amp;#x26;s)?;    Ok(s.to_string())}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This is convenient because we don’t want any user of our crate to bother with this function which is just an implementation detail that we might decide to change in the future.&lt;/p&gt;
&lt;h2 id=&quot;convert-a-string-to-anything&quot;&gt;Convert a string to anything&lt;/h2&gt;
&lt;p&gt;Another great suggestion from Tim to improve the ergonomics of the JWT parsing library was to implement the &lt;a href=&quot;https://doc.rust-lang.org/std/str/trait.FromStr.html&quot;&gt;&lt;code&gt;str::FromStr&lt;/code&gt; trait&lt;/a&gt; for the &lt;code&gt;Token&lt;/code&gt; type.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;FromStr&lt;/code&gt; trait is a special Rust trait that allows to convert a string into any type that implements the trait.&lt;/p&gt;
&lt;p&gt;This trait is already implemented in some standard type like &lt;code&gt;int32&lt;/code&gt; and is what allows us to convert a string to an &lt;code&gt;int32&lt;/code&gt; as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;1987&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;i32&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;unwrap&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;let value = &amp;#x22;1987&amp;#x22;;let result = value.parse::&lt;i32&gt;().unwrap();&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;By the way, if you find the syntax &lt;code&gt;function::&amp;#x3C;type&gt;()&lt;/code&gt; weird, don’t worry, we found it a bit “unfriendly” too. Once we discovered it is called &lt;em&gt;“turbofish”&lt;/em&gt; we couldn’t help but to fall in love with it. You can learn more about it here: &lt;a href=&quot;https://matematikaadit.github.io/posts/rust-turbofish.html&quot;&gt;Where to put the turbofish&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Don’t worry, if you still don’t like the turbofish syntax, you can rewrite the code above using type hints as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;1987&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;i32&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;unwrap&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;let value = &amp;#x22;1987&amp;#x22;;let result : i32 = value.parse().unwrap();&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The official docs as a great example that shows how the &lt;code&gt;str::FromStr&lt;/code&gt; trait can be very valuable to implement in your custom types. We are going to try to take this example and present it here in a slightly simplified fashion.&lt;/p&gt;
&lt;p&gt;Imagine you have defined a &lt;code&gt;Point&lt;/code&gt; type as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;#[derive(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Debug&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;PartialEq&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Point&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;i32&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;i32&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;#[derive(Debug, PartialEq)]struct Point {    x: i32,    y: i32}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now imagine you are processing data from a text source, let’s say a file, and in there points are encoded in a string format such as &lt;code&gt;17,22&lt;/code&gt;. Wouldn’t it be nice to be able to easily turn this format of strings into &lt;code&gt;Point&lt;/code&gt; values?&lt;/p&gt;
&lt;p&gt;Well, let’s enable this using the &lt;code&gt;str::FromStr&lt;/code&gt; trait:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;std&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;FromStr&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;std&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;num&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;ParseIntError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;#[derive(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Debug&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Point&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;i32&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;i32&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;FromStr&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Point&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;ParseIntError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;from_str&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;mut&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;parts&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;split&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;,&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;x_str&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;parts&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;unwrap_or&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;y_str&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;parts&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;unwrap_or&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;x_str&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;i32&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt;()?;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;y_str&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;i32&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt;()?;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Ok&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Point&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;main&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;17,22&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;point&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Point&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;unwrap&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{:?}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;point&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Point { x: 17, y: 22 }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;use std::str::FromStr;use std::num::ParseIntError;#[derive(Debug)]struct Point {    x: i32,    y: i32}impl FromStr for Point {    type Err = ParseIntError;    fn from_str(s: &amp;#x26;str) -&gt; Result&lt;Self, Self::Err&gt; {        let mut parts = s.split(&amp;#x22;,&amp;#x22;);        let x_str = parts.next().unwrap_or(&amp;#x22;0&amp;#x22;);        let y_str = parts.next().unwrap_or(&amp;#x22;0&amp;#x22;);        let x = x_str.parse::&lt;i32&gt;()?;        let y = y_str.parse::&lt;i32&gt;()?;        Ok(Point { x, y })    }}fn main() {    let value = &amp;#x22;17,22&amp;#x22;;    let point = value.parse::&lt;Point&gt;().unwrap();    println!(&amp;#x22;{:?}&amp;#x22;, point); // Point { x: 17, y: 22 }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;As you can see from the example above, the &lt;code&gt;str::FromStr&lt;/code&gt; trait has the following spec:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;FromStr&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;YourType&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;YourErrorType&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;from_str&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// process the string `s` and return a Result&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// either a Err(YourErrorType) or&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Ok&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;YourType&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;impl FromStr for YourType {    type Err = YourErrorType;    fn from_str(s: &amp;#x26;str) -&gt; Result&lt;Self, Self::Err&gt; {        // process the string &amp;#x60;s&amp;#x60; and return a Result        // either a Err(YourErrorType) or        Ok(YourType{})    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In our project it was rather trivial to implement this trait, because our &lt;code&gt;parse&lt;/code&gt; function matches quite closely the signature of the &lt;code&gt;from_str&lt;/code&gt; method defined in the &lt;code&gt;str::FromStr&lt;/code&gt; trait:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;FromStr&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Token&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;JWTParsePartError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;from_str&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;impl FromStr for Token {    type Err = JWTParsePartError;    fn from_str(s: &amp;#x26;str) -&gt; Result&lt;Self, Self::Err&gt; {        parse(s)    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This allows for the following syntax:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;token&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;jwt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Token&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;unwrap&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;let token = &amp;#x22;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c&amp;#x22;.parse::&lt;jwt::Token&gt;().unwrap();&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;or, if you still hate the poor turbofish:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;token&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;jwt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Token&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;unwrap&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;let token: jwt::Token = &amp;#x22;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c&amp;#x22;.parse().unwrap();&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;accept-any-type-that-can-be-converted-to-string&quot;&gt;Accept any type that can be converted to string&lt;/h2&gt;
&lt;p&gt;For better or for worse, Rust is famous for having a number of different types to represent strings. The most famous are &lt;a href=&quot;https://doc.rust-lang.org/stable/rust-by-example/std/str.html&quot;&gt;&lt;code&gt;String&lt;/code&gt; and &lt;code&gt;&amp;#x26;str&lt;/code&gt;&lt;/a&gt; but from time to time we have seen even other types like &lt;a href=&quot;https://doc.rust-lang.org/std/ffi/struct.CStr.html&quot;&gt;&lt;code&gt;CStr&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://doc.rust-lang.org/std/ffi/struct.OsStr.html&quot;&gt;&lt;code&gt;OsStr&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;During the review process, Tim recommended making our public API more flexible by supporting “every type that can be converted to a string”.&lt;/p&gt;
&lt;p&gt;The way we can achieve that is by leveraging the &lt;a href=&quot;https://doc.rust-lang.org/std/convert/trait.AsRef.html&quot;&gt;&lt;code&gt;std::convert::AsRef&lt;/code&gt;&lt;/a&gt; trait.&lt;/p&gt;
&lt;p&gt;The official documentation starts with a “not very friendly” opening (at least for Rust noobs like ourselves), but then it provides a great example that makes quite obvious how to use this trait to support any type of string:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;is_hello&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;AsRef&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;   &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;assert_eq!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;hello&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;as_ref&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;hello&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;is_hello&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;hello&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;to_string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;is_hello&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;s&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;fn is_hello&lt;T: AsRef&lt;str&gt;&gt;(s: T) {   assert_eq!(&amp;#x22;hello&amp;#x22;, s.as_ref());}let s = &amp;#x22;hello&amp;#x22;;is_hello(s);let s = &amp;#x22;hello&amp;#x22;.to_string();is_hello(s);&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Essentially, whenever you want to accept “anything that can be converted to a string” you can use the following recipe:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make your function accept an argument &lt;code&gt;x&lt;/code&gt; of generic type &lt;code&gt;T&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Define &lt;code&gt;T&lt;/code&gt; so that it must implement the trait &lt;code&gt;AsRef&amp;#x3C;str&gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;In your function body get the actual &lt;code&gt;str&lt;/code&gt; value from &lt;code&gt;x&lt;/code&gt; using &lt;code&gt;x.as_ref()&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As you can see from the example above, with this recipe, we can pass both &lt;code&gt;&amp;#x26;str&lt;/code&gt; and &lt;code&gt;String&lt;/code&gt; values to the &lt;code&gt;is_hello&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Applying this pattern to our code was quite straightforward. Also, since our public surface is quite small, we only needed to change the &lt;code&gt;jwt::parse&lt;/code&gt; function as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;AsRef&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;token&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Token&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;JWTParsePartError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;mut&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;parts&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;token&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;as_ref&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;split&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;.&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;pub fn parse&lt;T: AsRef&lt;str&gt;&gt;(token: T) -&gt; Result&lt;Token, JWTParsePartError&gt; {    let mut parts = token.as_ref().split(&amp;#x27;.&amp;#x27;);    // ...}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;remove-code-duplication&quot;&gt;Remove code duplication&lt;/h2&gt;
&lt;p&gt;One of the things that amazed us when we started playing with Rust was to discover that Rust &lt;a href=&quot;https://doc.rust-lang.org/reference/statements-and-expressions.html&quot;&gt;&lt;em&gt;is primarily an expression language&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In practice, this means that most syntax elements, including &lt;code&gt;if-else&lt;/code&gt; and &lt;code&gt;match&lt;/code&gt;, once evaluated will produce a value that can be carried over to other expressions or assigned to a variable.&lt;/p&gt;
&lt;p&gt;Coming from languages that don’t have this capability, we easily forget to take advantage of this characteristic of Rust and we end up writing code that contains duplication or that is more verbose than necessary.&lt;/p&gt;
&lt;p&gt;Tim spotted a few places where we could get rid of annoying code duplication by simply using &lt;code&gt;match&lt;/code&gt; and &lt;code&gt;if-else&lt;/code&gt; in a different way. This made us go through the code base of our crate and find other places where we could improve readability and make our code more idiomatic.&lt;/p&gt;
&lt;p&gt;Let’s show some examples:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;matches&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;is_present&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;header&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;jwt_token&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.header.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;to_string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;jwt_token&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.body.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;to_string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;if matches.is_present(&amp;#x22;header&amp;#x22;) {    println!(&amp;#x22;{}&amp;#x22;, jwt_token.header.to_string());} else {    println!(&amp;#x22;{}&amp;#x22;, jwt_token.body.to_string());}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This code has clearly some repetition. It is not terrible, but it seems unnecessary to have to repeat the &lt;code&gt;println!()&lt;/code&gt; macro invocation and the &lt;code&gt;to_string()&lt;/code&gt; call.&lt;/p&gt;
&lt;p&gt;We ended up refactoring this as follows:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;part&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;matches&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;is_present&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;header&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;jwt_token&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.header&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;jwt_token&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.body&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;part&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;to_string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;let part = if matches.is_present(&amp;#x22;header&amp;#x22;) {    jwt_token.header} else {    jwt_token.body};println!(&amp;#x22;{}&amp;#x22;, part.to_string());&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Once you know that &lt;code&gt;if-else&lt;/code&gt; expressions will produce a value (depending on which branch will be selected at runtime), this alternative looks more readable. Also this refactoring makes quite clear that this code has essentially 2 parts: select a part, then print it on the standard output.&lt;/p&gt;
&lt;p&gt;Another interesting example in our code base involved the &lt;code&gt;match&lt;/code&gt; expression. This was the code before the refactoring:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Display&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;JWTParseError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;mut&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Formatter&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;match&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;JWTParseError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;MissingSection&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;write!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Missing token section&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;to_string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;JWTParseError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;InvalidUtf8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;write!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;UTF8 error, {}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;JWTParseError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;InvalidBase64&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;write!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Base64 error, {}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;JWTParseError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;InvalidJSON&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;write!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;JSON error, {}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;impl fmt::Display for JWTParseError {    fn fmt(&amp;#x26;self, f: &amp;#x26;mut fmt::Formatter) -&gt; fmt::Result {        match self {            JWTParseError::MissingSection() =&gt; write!(f, &amp;#x22;{}&amp;#x22;, &amp;#x22;Missing token section&amp;#x22;.to_string()),            JWTParseError::InvalidUtf8(e) =&gt; write!(f, &amp;#x22;UTF8 error, {}&amp;#x22;, e),            JWTParseError::InvalidBase64(e) =&gt; write!(f, &amp;#x22;Base64 error, {}&amp;#x22;, e),            JWTParseError::InvalidJSON(e) =&gt; write!(f, &amp;#x22;JSON error, {}&amp;#x22;, e),        }    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Applying the same principle as before we refactored the code above to this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Display&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;JWTParseError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;mut&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Formatter&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) -&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;match&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;JWTParseError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;MissingSection&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Missing token section&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;to_string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;JWTParseError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;InvalidUtf8&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;format!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;UTF8 error, {}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;JWTParseError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;InvalidBase64&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;format!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Base64 error, {}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;JWTParseError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;InvalidJSON&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;format!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;JSON error, {}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;write!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;impl fmt::Display for JWTParseError {    fn fmt(&amp;#x26;self, f: &amp;#x26;mut fmt::Formatter) -&gt; fmt::Result {        let message = match self {            JWTParseError::MissingSection() =&gt; &amp;#x22;Missing token section&amp;#x22;.to_string(),            JWTParseError::InvalidUtf8(e) =&gt; format!(&amp;#x22;UTF8 error, {}&amp;#x22;, e),            JWTParseError::InvalidBase64(e) =&gt; format!(&amp;#x22;Base64 error, {}&amp;#x22;, e),            JWTParseError::InvalidJSON(e) =&gt; format!(&amp;#x22;JSON error, {}&amp;#x22;, e),        };        write!(f, &amp;#x22;{}&amp;#x22;, message)    }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Again, the trick here is to assign the result of the match expression to a variable (&lt;code&gt;message&lt;/code&gt; in this particular case) and then we can re-use that variable in the next step.&lt;/p&gt;
&lt;p&gt;Another cool thing that we discovered is that, by using &lt;a href=&quot;https://github.com/rust-lang/rust-clippy&quot;&gt;clippy&lt;/a&gt; as a linter, it will help you out to spot some of these improvements.&lt;/p&gt;
&lt;p&gt;For instance, the first time we tried to improve the readability of the &lt;code&gt;if-else&lt;/code&gt; expression previously mentioned we ended up using a &lt;code&gt;match&lt;/code&gt; expression unnecessarily:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;part&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;match&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;matches&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;is_present&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;header&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;jwt_token&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.header,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; =&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;jwt_token&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.body,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;println!&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;part&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;to_string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;let part = match matches.is_present(&amp;#x22;header&amp;#x22;) {    true =&gt; jwt_token.header,    false =&gt; jwt_token.body,};println!(&amp;#x22;{}&amp;#x22;, part.to_string());&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;When we run clippy on this code, it did trigger the &lt;a href=&quot;https://rust-lang.github.io/rust-clippy/master/index.html#match_bool&quot;&gt;&lt;code&gt;match_bool&lt;/code&gt;&lt;/a&gt; rule and that it is suggested to refactor this with an &lt;code&gt;if-else&lt;/code&gt; expression:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;part&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;matches&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;is_present&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;header&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;jwt_token&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.header&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;jwt_token&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.body&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;let part = if matches.is_present(&amp;#x22;header&amp;#x22;) {    jwt_token.header} else {    jwt_token.body};&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Which is indeed more readable. Another lesson learned: trust linters!&lt;/p&gt;
&lt;p&gt;In short, these types of change helped us to reduce the amount of inline composition and to make the code more sequential and easy to follow.&lt;/p&gt;
&lt;h2 id=&quot;improve-tests-for-invalid-strings&quot;&gt;Improve tests for invalid strings&lt;/h2&gt;
&lt;p&gt;Another thing that Tim recommended us to do was to improve our coverage on testing different types of input. He tried to run our JWT parser against strings with non-utf8 characters and strings containing null bytes to see whether our code would handle that correctly (returning an error) or whether it would just panic.&lt;/p&gt;
&lt;p&gt;The idea is to try to avoid panics at all costs and make sure all possible errors are handled and propagated correctly.&lt;/p&gt;
&lt;p&gt;This pushed us to increase our test coverage adding a few more tests as you can see in &lt;a href=&quot;https://github.com/lmammino/jwtinfo/pull/28/files&quot;&gt;this PR&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Another interesting recommendation was to use something like &lt;a href=&quot;https://github.com/BurntSushi/quickcheck&quot;&gt;quickcheck&lt;/a&gt; to do fuzzy testing on our input. Although this seems like an extremely interesting thing to do, we haven’t got time yet to play with this idea.&lt;/p&gt;
&lt;h2 id=&quot;shell-scripts-deserve-some-love-too&quot;&gt;Shell scripts deserve some love too&lt;/h2&gt;
&lt;p&gt;As a last point, Tim had a look at our &lt;a href=&quot;https://github.com/lmammino/jwtinfo/blob/master/install.sh&quot;&gt;cross-system installation script&lt;/a&gt; and immediately noticed our poor use of Bash scripting.&lt;/p&gt;
&lt;p&gt;The main advice here was to use some shell linter like &lt;a href=&quot;https://www.shellcheck.net&quot;&gt;Shellcheck&lt;/a&gt;. Tim himself, ran the script against the linter by copy pasting the code on the web page and submitted a PR with some improvements.&lt;/p&gt;
&lt;p&gt;Shellcheck can be used as a command line tool too, so it would be nice in feature release to integrate in our automated tests.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This concludes our recap article. We don’t have any special rule of thumb except that the Rust ride was quite fun for us so far. It has been a bumpy road but thanks to the amazing open source community and people like Tim, the road to learn Rust can become much smoother.&lt;/p&gt;
&lt;p&gt;Our final word of advice is that, if you are learning Rust, or any other technology for what matters, don’t be afraid to start public open source projects and ask for help and reviews. Even better if you share this journey with some friends.&lt;/p&gt;
&lt;p&gt;At the end of the day, all that matters is learning new things and having fun!&lt;/p&gt;
&lt;p&gt;We take one more opportunity to thank Tim for the great support here and, if you like Rust, we do recommend you to follow him on &lt;a href=&quot;https://twitter.com/timClicks&quot;&gt;Twitter&lt;/a&gt;, &lt;a href=&quot;https://www.twitch.tv/timclicks&quot;&gt;Twitch&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/channel/UClny6qj9Mv7uFo9XGUGYQBA&quot;&gt;Youtube&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Take care! 🙌&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/learning-rust-through-open-source-and-live-code-reviews.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/learning-rust-through-open-source-and-live-code-reviews.png" width="1200" height="630"/></media:content><category>rust</category><author>Luciano Mammino</author><comments>https://loige.co/learning-rust-through-open-source-and-live-code-reviews/#comments</comments><enclosure url="https://loige.co/og/learning-rust-through-open-source-and-live-code-reviews.png" length="0" type="image/png"/></item><item><title>AWS Solution Architect Professional exam, my notes and tips</title><link>https://loige.co/aws-solution-architect-professional-exam-notes-tips/</link><guid isPermaLink="true">https://loige.co/aws-solution-architect-professional-exam-notes-tips/</guid><description>The AWS Solutions Architect Professional certification is one of the toughest IT certifications. This post shares preparation tips, exam strategies, study resources, and sample questions to help you succeed.</description><pubDate>Tue, 26 Apr 2022 18:20:00 GMT</pubDate><content:encoded>&lt;p&gt;Hello everyone, I am really happy to share with you that I recently got my AWS Solution Architect Professional certification (SAP-C01) 🎉&lt;/p&gt;
&lt;p&gt;In this article I talk about my experience with the exam, how I prepared for it and share a few tips that can, hopefully, help you if you are preparing for the exam.&lt;/p&gt;
&lt;h2 id=&quot;who-is-the-aws-solution-architect-professional-certification-for&quot;&gt;Who is the AWS Solution Architect Professional certification for&lt;/h2&gt;
&lt;p&gt;I’d recommend you embarking on this challenge only if you already have a few years of AWS experience and you already managed to explore a few different services and different types of architectures.&lt;/p&gt;
&lt;p&gt;This certification is for those who want to have a comprehensive view of what’s possible with AWS and that are aiming to be able to advise about the best architectures for specific problems.&lt;/p&gt;
&lt;p&gt;In my view, this certification is for you if you are working as a &lt;strong&gt;AWS cloud consultant&lt;/strong&gt; (or you want to be one) or you are aiming to get an &lt;strong&gt;architect&lt;/strong&gt; role at a company with a significant footprint on AWS.&lt;/p&gt;
&lt;p&gt;If you have already taken other AWS certifications that would also be very beneficial for you. This is probably the hardest of AWS certification so having experienced the whole process with other AWS certifications will help.&lt;/p&gt;
&lt;p&gt;In my case, &lt;a href=&quot;/aws-solution-architect-associate-exam-notes-tips&quot;&gt;I took the AWS Solution Architect associate certification&lt;/a&gt; 3 years ago. If you have less than 2 years of experience with AWS, I’d recommend taking this other certification first. You can read &lt;a href=&quot;/aws-solution-architect-associate-exam-notes-tips&quot;&gt;my notes and tips&lt;/a&gt; about that particular experience!&lt;/p&gt;
&lt;h2 id=&quot;exam-structure&quot;&gt;Exam Structure&lt;/h2&gt;
&lt;p&gt;The AWS Solution Architect is probably the thoughest exams I had to do to get an IT certification.&lt;/p&gt;
&lt;p&gt;The exam is not easy, it requires quite a lot of focus.&lt;/p&gt;
&lt;p&gt;There are tons of questions, every question is very verbose and getting the right answer while trying to manage your time, can be challenging. On top of that, you need a very broad knowledge about AWS services and different types of architectural concerns.&lt;/p&gt;
&lt;p&gt;The exam is a multiple answer question. In it’s current incarnation (2022) there are &lt;strong&gt;75 questions&lt;/strong&gt; and you have &lt;strong&gt;3 hours&lt;/strong&gt; to complete it. This gives you about 2 minutes per question.&lt;/p&gt;
&lt;p&gt;If you think that’s plenty of time, let’s have a look at one of the example questions. Start a time, NOW! ⏱&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A company has two AWS accounts: one for production workloads and one for development workloads.
Creating and managing these workloads are a development team and an operations team. The company
needs a security strategy that meets the following requirements:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Developers need to create and delete development application infrastructure.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operators need to create and delete both development and production application infrastructure.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Developers should have no access to production infrastructure.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;All users should have a single set of AWS credentials.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What strategy meets these requirements?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A) In the development account:
&lt;ul&gt;
&lt;li&gt;Create a development IAM group with the ability to create and delete application infrastructure.&lt;/li&gt;
&lt;li&gt;Create an IAM user for each operator and developer and assign them to the development group.
In the production account:&lt;/li&gt;
&lt;li&gt;Create an operations IAM group with the ability to create and delete application infrastructure.&lt;/li&gt;
&lt;li&gt;Create an IAM user for each operator and assign them to the operations group.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;B) In the development account:
&lt;ul&gt;
&lt;li&gt;Create a development IAM group with the ability to create and delete application infrastructure.&lt;/li&gt;
&lt;li&gt;Create an IAM user for each developer and assign them to the development group.&lt;/li&gt;
&lt;li&gt;Create an IAM user for each operator and assign them to the development group and the operations group in the production account.
In the production account:&lt;/li&gt;
&lt;li&gt;Create an operations IAM group with the ability to create and delete application infrastructure.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;C) In the development account:
&lt;ul&gt;
&lt;li&gt;Create a shared IAM role with the ability to create and delete application infrastructure in the production account.&lt;/li&gt;
&lt;li&gt;Create a development IAM group with the ability to create and delete application infrastructure.&lt;/li&gt;
&lt;li&gt;Create an operations IAM group with the ability to assume the shared role.&lt;/li&gt;
&lt;li&gt;Create an IAM user for each developer and assign them to the development group.&lt;/li&gt;
&lt;li&gt;Create an IAM user for each operator and assign them to the development group and the operations group.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;D) In the development account:
&lt;ul&gt;
&lt;li&gt;Create a development IAM group with the ability to create and delete application infrastructure.&lt;/li&gt;
&lt;li&gt;Create an operations IAM group with the ability to assume the shared role in the production account.&lt;/li&gt;
&lt;li&gt;Create an IAM user for each developer and assign them to the development group.&lt;/li&gt;
&lt;li&gt;Create an IAM user for each operator and assign them to the development group and the operations group.
In the production account:&lt;/li&gt;
&lt;li&gt;Create a shared IAM role with the ability to create and delete application infrastructure.&lt;/li&gt;
&lt;li&gt;Add the development account to the trust policy for the shared role.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;OK, time off! ⏱&lt;/p&gt;
&lt;p&gt;How long did it take you to read and make sense of this literal wall of text?! Do you already know what’s the right answer? 😅&lt;/p&gt;
&lt;p&gt;I am probably slow at reading, but it took me about 2 minutes just to read this!&lt;/p&gt;
&lt;p&gt;Some questions are even trickier because you’ll need to pick more than one answer!&lt;/p&gt;
&lt;p&gt;The point is that you’ll need to be able to decide on your answer fast. And you will also need to be able to keep your focus for 3 hours straight!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;🔥 First tip&lt;/strong&gt;: if English is not your primary language you can request extra time when booking your exam, or do the exam in other languages (French, German, Italian, Japanese, Korean, Portuguese, Simplified Chinese, or Spanish).&lt;/p&gt;
&lt;p&gt;I didn’t think I needed this and I went for the English version without extra time. I had to rush through the last 5 questions, so, in retrospective, it was a mistake not to take advantage of this!&lt;/p&gt;
&lt;p&gt;I’ll share a few more tips to maximise your chances of succes later in this article!&lt;/p&gt;
&lt;p&gt;Meanwhile, if you are curious to see more example questions, there is an &lt;a href=&quot;https://d1.awsstatic.com/training-and-certification/docs-sa-pro/AWS-Certified-Solutions-Architect-Professional_Sample-Questions.pdf&quot;&gt;official set of example questions for the Solution Architect Professional exam provided by AWS&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;exam-topics-and-required-knowledge&quot;&gt;Exam topics and required knowledge&lt;/h2&gt;
&lt;p&gt;There are 5 &lt;em&gt;domains&lt;/em&gt; of knowledge in which the various questions are grouped:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Domain 1&lt;/strong&gt;: Design for Organizational Complexity (12.5% of the exam)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Domain 2&lt;/strong&gt;: Design for New Solutions (31%  of the exam)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Domain 3&lt;/strong&gt;: Migration Planning (15%  of the exam)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Domain 4&lt;/strong&gt;: Cost Control (12.5%  of the exam)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Domain 5&lt;/strong&gt;: Continuous Improvement (29%  of the exam)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In terms of overall knowledge, these are some of the topics that AWS recommends you to be comfortable with before taking the exam:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Familiarity with AWS CLI and APIs.&lt;/li&gt;
&lt;li&gt;Be comfortable with CloudFormation.&lt;/li&gt;
&lt;li&gt;Be able to understand Billing and to use the web console.&lt;/li&gt;
&lt;li&gt;Know how to use a scripting language.&lt;/li&gt;
&lt;li&gt;Know enough about running applications on Windows and Linux systems and how to keep them up to date.&lt;/li&gt;
&lt;li&gt;Ability to provide guidance on the architectural design across multiple applications and projects of the enterprise as well as an ability to map business objectives to application/architecture requirements.&lt;/li&gt;
&lt;li&gt;Ability to evaluate cloud application requirements and make architectural recommendations for implementation, deployment, and provisioning applications on AWS.&lt;/li&gt;
&lt;li&gt;Ability to design a hybrid architecture using key AWS technologies (e.g., VPN, AWS Direct Connect) as well as a continuous integration and deployment process.&lt;/li&gt;
&lt;li&gt;Be able to explain and apply the five pillars of the AWS Well-Architected Framework.&lt;/li&gt;
&lt;li&gt;Architect a continuous integration/continuous delivery (CI/CD) process.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Yes, it’s quite a big surface of knowledge and this is probably not even a comprehensive list.&lt;/p&gt;
&lt;p&gt;If you want a bit more detail on what kind of topics and services you need to be comfortable with you can Download the &lt;a href=&quot;https://d1.awsstatic.com/training-and-certification/docs-sa-pro/AWS-Certified-Solutions-Architect-Professional_Exam-Guide.pdf&quot;&gt;official Solution Architect Professional exam guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;preparation&quot;&gt;Preparation&lt;/h2&gt;
&lt;p&gt;Ok, if you are still up for this, let’s see how you can prepare yourself to smash this challenging exam! 💪&lt;/p&gt;
&lt;p&gt;Well… unfortunately, I don’t think there is a bullet-proof method to pass this exam. This exam takes a good mixture of expertise, focus and (of course) a bit of luck. You should do your best to arrive prepared at the exam, but I also recommend you account for a good chance of failure. It’s not a shame to fail the exam and you can always try it again later.&lt;/p&gt;
&lt;p&gt;So, how did I prepare myself?&lt;/p&gt;
&lt;p&gt;I have been lucky to have been exposed quite a lot to various AWS projects in the last 5-6 years. This has given me a good breadth of knowledge and confidence. I have been working in a mixture of roles shifting from software engineering to architecture. I have architected, built and deployed serverless solutions, but also more traditional solutions based on EC2 instances and containers. I also had numerous chances to explore event driven architectures and use services like SQS, SNS, EventBridge and Kinesis.&lt;/p&gt;
&lt;p&gt;With that being said, I don’t think this amount of practical experience was nearly enough to walk into the exam!&lt;/p&gt;
&lt;p&gt;But how did I know that? Well, I didn’t… I was actually quite confident about my skills at first! Until I got knocked out by the first exam simulation…&lt;/p&gt;
&lt;h3 id=&quot;exam-simulations&quot;&gt;Exam simulations&lt;/h3&gt;
&lt;p&gt;The first thing you should really do to asses where you stand is to take an exam simulation. An exam simulation will present you 75 questions similar to the ones you might find during the real exam and you’ll have 3 hours to answer them.&lt;/p&gt;
&lt;p&gt;Those simulations are available on a number of platforms. I have tried 2 of them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.udemy.com/course/aws-solutions-architect-professional-practice-exams-amazon/&quot;&gt;AWS Certified Solutions Architect Professional Practice Exam&lt;/a&gt; on Udemy, by Jon Bonso (Tutorials Dojo).&lt;/li&gt;
&lt;li&gt;AWS Certified Solutions Architect - Professional 2020 on &lt;a href=&quot;https://acloudguru.com/&quot;&gt;A Cloud Guru&lt;/a&gt;, by Scott Pletcher.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I really liked the Udemy ones for several reasons.&lt;/p&gt;
&lt;p&gt;First of all, you can pause your exam. I know this is not really realistic, but it’s a great way to allow you to practice even when you don’t have a block of 3 full hours available to you.&lt;/p&gt;
&lt;p&gt;Secondly, at the end of a simulation, you get an overview of all the questions. For every question you get a quite lengthy explaination about how you should have interpreted the question and a walkthrough over all the possible answer. This can teach you how to analyse questions and answers and it will help you train the right muscles to spot correct answers and recognize and avoid wrong answers (&lt;em&gt;distractors&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Once you complete a simulation you can assess where you stand against the different domains of the exam. Where you weakness and strengths lies and where you need to study and practice more.&lt;/p&gt;
&lt;p&gt;The Udemy course gives you four different variations of the exam, so you get a total of 300 questions to practice with!&lt;/p&gt;
&lt;h3 id=&quot;study-material&quot;&gt;Study material&lt;/h3&gt;
&lt;p&gt;Once you have identified your gaps, you need to study!&lt;/p&gt;
&lt;p&gt;I found A Cloud Guru to be one of the best resources out there. The AWS Certified Solutions Architect Professional course by Scott Pletcher is very broad and informative. Scott keeps it quite entertaining with occasional stories and jokes and there are quite a few interactive labs for you to practice what you learn through the course.&lt;/p&gt;
&lt;p&gt;Doing the full course could be quite time consuming (almost 30 hours of video content!), but if you are in a rush you can only pick the chapters that you need the most. That table of contents is really well structured and you can easily jump around.&lt;/p&gt;
&lt;p&gt;One caveat is that what A Cloud Guru gives you is not necessarily enough. In some cases the videos and the labs only scratch the surface of certain topics and you might still struggle to answer some of the question.&lt;/p&gt;
&lt;p&gt;In those cases, Scott is very upfront and gives you a bunch of additional study material published for free directly from AWS. Make sure not to ignore these papers because they can make a big difference in your understanding of AWS and in getting you ready for the exam!&lt;/p&gt;
&lt;p&gt;Another great resource is AWS Skill Builders, which has an entire section on &lt;a href=&quot;https://explore.skillbuilder.aws/learn/course/external/view/elearning/34/exam-readiness-aws-certified-solutions-architect-professional?sap=sec&amp;#x26;sec=prep&quot;&gt;Exam Readiness: AWS Certified Solutions Architect – Professional&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I only skimmed through this one, so I can’t vouch 100% for this, but it seems like a great FREE alternative to what A Cloud Guru can offer.&lt;/p&gt;
&lt;p&gt;Check out also the FAQ and the White Papers published on the &lt;a href=&quot;https://aws.amazon.com/certification/certified-solutions-architect-professional/&quot;&gt;official page for the AWS Certified Solutions Architect - Professional certification&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;recommended-strategy&quot;&gt;Recommended strategy&lt;/h2&gt;
&lt;p&gt;Here’s my very personal recommendation on how to prepare and approach the exam.&lt;/p&gt;
&lt;h3 id=&quot;before-the-exam&quot;&gt;Before the exam&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Do a couple of exam simulations on Udemy.&lt;/li&gt;
&lt;li&gt;Don’t worry too much about your score (I failed almost all of them!), but focus on the questions you failed. Read the explanation and make sure to understand if you need to research more about the topic.&lt;/li&gt;
&lt;li&gt;Compile a list of all the topics you need to research more about (your gaps).&lt;/li&gt;
&lt;li&gt;Find study material (A Cloud Guru, YouTube, official AWS material, etc.) and try to fill the gaps.&lt;/li&gt;
&lt;li&gt;Do more exam simulations.&lt;/li&gt;
&lt;li&gt;Try to do a couple more of exam simulations without pausing the exam.&lt;/li&gt;
&lt;li&gt;Don’t wait for your simulation score to be over 75% before you try the real exam, just make sure your score has improved and that you feel much more confident.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;during-the-exam&quot;&gt;During the exam&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Read the question carefully and try to understand what are the main keywords and what’s the context. After a few simulations you should know what to expect and you should be able to skim through the question quickly.&lt;/li&gt;
&lt;li&gt;But if you feel you haven’t fully understood the question take the time to read it again.&lt;/li&gt;
&lt;li&gt;Manage your time. Ideally you shouldn’t be spending more than 2 minutes per question, but sometimes there are question that require you more time. Don’t stress too much out if you are taking to long for a given question, there will be questions that you’ll be able to answer in less than 2 minutes and those will help you to balance things out. Make sure though not to spend too much time on a given question. If it’s taking you more than 4 minutes, you should probably skip it (or even better give a temporary answer) and come back to it later.&lt;/li&gt;
&lt;li&gt;You can flag questions for review. This means that flagged questions will be highlighted and it will be easier for you to get back to them if you have extra time and want to review the answer.&lt;/li&gt;
&lt;li&gt;A lot of questions don’t have absolutely objective answers. Actually most questions are arguable (in my opinion). In those cases try to go by exclusion and find reasons not to pick particular answers. Try also to wear the hat of AWS: ask yourself &lt;em&gt;what would AWS itself most likely recommend?&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;after-the-exam&quot;&gt;After the exam&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;If you passed it… well, good job! Time to brag with your friends and co-workers and celebrate!&lt;/li&gt;
&lt;li&gt;If you didn’t pass it… no worries! You have probably learned a lot anyway. Go back to more simulations and study material and try again in a few months! Next time will certainly go better!&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;my-study-notes&quot;&gt;My Study notes&lt;/h2&gt;
&lt;p&gt;Here’s a list of notes about topics that I didn’t really know about and I had to research a little bit. This is no way comprehensive but maybe it can help you to find gaps in your knowledge. I basically build this list out of answers I failed during the simulations, so these were basically part of my knowledge gaps!&lt;/p&gt;
&lt;h3 id=&quot;alexa-for-business&quot;&gt;Alexa for business&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;A service that allows you to provision Alexa Echo devices for office use.&lt;/li&gt;
&lt;li&gt;Can be integrated with office resources (e.g. calendar, room booking systems, shared files, video conference tools, etc.).&lt;/li&gt;
&lt;li&gt;Then Echo devices can be used to answer business questions, book meetings or other resources.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;amazon-connect&quot;&gt;Amazon Connect&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Cloud based contact center (system to allow communication between companies and the general public, e.g. support call centers)&lt;/li&gt;
&lt;li&gt;Main features: Provides skill based routing, Automatic call distribution, Call recording, Reporting&lt;/li&gt;
&lt;li&gt;Allows to design automated “Contact flows” that can direct the user to the right operator (“press X if you need to do Y”)&lt;/li&gt;
&lt;li&gt;The contact flows can be integrated with lambda to customise the flow programmatically decisions for the workflow (e.g. fetch a reservation for the caller and decide the next step based on the state of the reservation)&lt;/li&gt;
&lt;li&gt;Provides an IVR (Interactive Voice Response) and records transcripts for every conversation / flow&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;amazon-kinesis-video-stream&quot;&gt;Amazon Kinesis Video Stream&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Different service from Kinesis Data Stream (it goes into an entirely different category)&lt;/li&gt;
&lt;li&gt;Cameras/microphones and other devices can use Kinesis video stream libraries (producer library) to publish data (real time or buffered)&lt;/li&gt;
&lt;li&gt;Data can be consumed in real time or buffered (saved durably in S3) - Real time vs batch approach&lt;/li&gt;
&lt;li&gt;Rekognition can be used to extract metadata from the stream&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;aws-networking-notes&quot;&gt;AWS Networking notes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Network ACL (NACL): firewall-like rules for entire vpc/subnets to enable/block traffic (stateless. Outgoing traffic for ephemeral ports needs to be specified explicitly )&lt;/li&gt;
&lt;li&gt;Security Groups: per instance firewall-like rules to enable disable traffic (stateful. E.g. if you allow incoming port 80, outgoing port for traffic coming through port 80 will be allowed as well)&lt;/li&gt;
&lt;li&gt;You can give a public IP to a Load Balancer either through a Network load balancer with Elastic IP or an Application Load Balancer with Gloabal Accelerator&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;aws-shield&quot;&gt;AWS Shield&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Service for DDoS attack protection.&lt;/li&gt;
&lt;li&gt;There is an Shield Advanced option. In addition to the network and transport layer protections that come with Standard, AWS Shield Advanced provides additional detection and mitigation against large and sophisticated DDoS attacks, near real-time visibility into attacks, and integration with AWS WAF.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cloudfront&quot;&gt;CloudFront&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;CloudFront signed cookies allow you to control who can access your content when you don’t want to change your current URLs or when you want to provide access to multiple restricted files, for example, all of the files in the subscribers’ area of a website. This topic explains the considerations when using signed cookies and describes how to set signed cookies using canned and custom policies.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;direct-connect&quot;&gt;Direct Connect&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Direct Connect can be used to connect an Amazon VPC to an On premise network&lt;/li&gt;
&lt;li&gt;Use Direct Connect link between the VPC and the on premise network&lt;/li&gt;
&lt;li&gt;Use a network device in the on-premise network that supports BGP and MD5 Authentication (needed to establish a Direct Connect link from your data center to your VPC)&lt;/li&gt;
&lt;li&gt;Direct Connect connections consist of a single connection between your network and AWS with no inherent redundancy.&lt;/li&gt;
&lt;li&gt;Traffic coming from on-prem via a Direct Connect connect is restricted from internet access.&lt;/li&gt;
&lt;li&gt;You must create a virtual interface (public, private or transit) in order to begin using your AWS Direct Connect connection.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;iam&quot;&gt;IAM&lt;/h3&gt;
&lt;h4 id=&quot;managed-policies&quot;&gt;Managed Policies&lt;/h4&gt;
&lt;p&gt;AWS managed policies &lt;strong&gt;don’t grant least privilege permissions&lt;/strong&gt;. You must consider the security risk of granting your principals more permissions than they need to do their job.&lt;/p&gt;
&lt;p&gt;You can attach AWS managed policies, including job functions, to any IAM identity. To switch to least privilege permissions, you can run &lt;strong&gt;AWS Identity and Access Management Access Analyzer&lt;/strong&gt; to monitor principals with AWS managed policies. After learning which permissions they are using, then you can write a custom policy or generate a policy with only the required permissions for your team. This is less secure, but provides more flexibility as you learn how your team is using AWS.&lt;/p&gt;
&lt;p&gt;AWS managed policies for job functions are designed to closely align to common job functions in the IT industry. You can use these policies to grant the permissions needed to carry out the tasks expected of someone in a specific job function. These policies consolidate permissions for many services into a single policy that’s easier to work with than having permissions scattered across many policies.&lt;/p&gt;
&lt;h5 id=&quot;most-common-managed-policies&quot;&gt;Most common managed policies&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/AdministratorAccess&quot;&gt;AdministratorAccess&lt;/a&gt;&lt;/strong&gt; his user has full access and can delegate permissions to every service and resource in AWS.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/job-function/Billing&quot;&gt;&lt;strong&gt;Billing&lt;/strong&gt;&lt;/a&gt; This user needs to view billing information, set up payments, and authorize payments. The user can monitor the costs accumulated for the entire AWS service.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/job-function/DatabaseAdministrator&quot;&gt;&lt;strong&gt;DatabaseAdministrator&lt;/strong&gt;&lt;/a&gt; This user sets up, configures, and maintains databases in the AWS Cloud.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/job-function/DataScientist&quot;&gt;&lt;strong&gt;DataScientist&lt;/strong&gt;&lt;/a&gt; This user runs Hadoop jobs and queries. The user also accesses and analyzes information for data analytics and business intelligence.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/PowerUserAccess&quot;&gt;&lt;strong&gt;PowerUserAccess&lt;/strong&gt;&lt;/a&gt;This user performs application development tasks and can create and configure resources and services that support AWS aware application development.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/job-function/NetworkAdministrator&quot;&gt;&lt;strong&gt;NetworkAdministrator&lt;/strong&gt;&lt;/a&gt; This user is tasked with setting up and maintaining AWS network resources.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/ReadOnlyAccess&quot;&gt;&lt;strong&gt;ReadOnlyAccess&lt;/strong&gt;&lt;/a&gt; This user requires read-only access to every resource in an AWS account.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/SecurityAudit&quot;&gt;&lt;strong&gt;SecurityAudit&lt;/strong&gt;&lt;/a&gt; This user monitors accounts for compliance with security requirements. This user can access logs and events to investigate potential security breaches or potential malicious activity.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/job-function/SupportUser&quot;&gt;&lt;strong&gt;SupportUser&lt;/strong&gt;&lt;/a&gt; This user contacts AWS Support, creates support cases, and views the status of existing cases.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/job-function/SystemAdministrator&quot;&gt;&lt;strong&gt;SystemAdministrator&lt;/strong&gt;&lt;/a&gt; This user sets up and maintains resources for development operations.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/job-function/ViewOnlyAccess&quot;&gt;&lt;strong&gt;ViewOnlyAccess&lt;/strong&gt;&lt;/a&gt; This user can view a list of AWS resources and basic metadata in the account across all services. The user cannot read resource content or metadata that goes beyond the quota and list information for resources.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;lex&quot;&gt;Lex&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Conversation interface service&lt;/li&gt;
&lt;li&gt;ASR (Automatic Speech Recognition) + NLU (Natural Language Understanding)&lt;/li&gt;
&lt;li&gt;Can understand voice and text (voice automation + chatbots)&lt;/li&gt;
&lt;li&gt;Based on intents (entities that define actions that the user might want to perform)&lt;/li&gt;
&lt;li&gt;An intent has “sample utterances” (example phrases that can be used to express the intent)&lt;/li&gt;
&lt;li&gt;An intent has “slots” (particular type of keywords that represent specific concepts in a phrase)&lt;/li&gt;
&lt;li&gt;A “slot” can have a type (e.g. color, dates, day of weeks, city, country, etc.)&lt;/li&gt;
&lt;li&gt;Slots can be used as a template variable in utterances (“Your trip is scheduled for {date}”)&lt;/li&gt;
&lt;li&gt;The response is generated statically (predefined phrases) or dinamically (through a lambda)&lt;/li&gt;
&lt;li&gt;Can be combined with comprehend for sentiment analysis&lt;/li&gt;
&lt;li&gt;It understands audio (Amazon Transcribe: speech to text)&lt;/li&gt;
&lt;li&gt;It can generate audio responses (Amazon Polly: text to speech)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;macie&quot;&gt;Macie&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Security tool that can be used to monitor events (Intelligent cloud protection)&lt;/li&gt;
&lt;li&gt;It can scan data uploaded to S3 and recognize sensitive information (e.g. API Keys, but also passport numbers or address)&lt;/li&gt;
&lt;li&gt;It can be used to detect anomalies in AWS API usage (e.g. it can detect if data is likely to have been stolen)&lt;/li&gt;
&lt;li&gt;It can be integrated with CloudWatch and SNS to alarm on potential threats&lt;/li&gt;
&lt;li&gt;It offers a dashboard that allows you to visualise the detected threats, but also all the AWS API calls (grouped by type but you can also drill down)&lt;/li&gt;
&lt;li&gt;Supports Lucene-style queries to search through the data&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;rpo-vs-rto&quot;&gt;RPO vs RTO&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Metrics for establishing and measuring good practices in backup and recovery of data (disaster recovery)&lt;/li&gt;
&lt;li&gt;RPO (Recovery Point Objective): Time between a good dataset (in the backup) and a disaster event.&lt;/li&gt;
&lt;li&gt;RTO (Recovery Time Objective):  Point in which the data is restored and operation continues.&lt;/li&gt;
&lt;li&gt;If RTO is 30 minutes that means that recovering from an incident should not take more than 30 minutes. You can also see that as the maximum time that a company is willing to keep a service unavailable&lt;/li&gt;
&lt;li&gt;RPO: before an incident occurs&lt;/li&gt;
&lt;li&gt;RTO: after an event occurs&lt;/li&gt;
&lt;li&gt;Reducing RPO and RTO have cost implications because it means more frequent backups and faster mechanism to recover from failure&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;s3&quot;&gt;S3&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Objects that are stored in your bucket before you set the versioning state have a version ID of &lt;code&gt;null&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;s3-select&quot;&gt;S3 Select&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Allows to query ONE s3 object and extract data from it without having to download the entire file locally&lt;/li&gt;
&lt;li&gt;It uses a subset of standard SQL for queries&lt;/li&gt;
&lt;li&gt;Supports CSV, JSON (also gzipped or bzipped) and parquet (non compressed)&lt;/li&gt;
&lt;li&gt;Supports files encrypted at rest&lt;/li&gt;
&lt;li&gt;Can query selectively part of a file (e.g. only the first 100Mb)&lt;/li&gt;
&lt;li&gt;It can be cheaper to get data out of S3 this way (not transferring large files outside AWS)&lt;/li&gt;
&lt;li&gt;It charges based on the amount of data scanned per query and the amount of data returned&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;snowball&quot;&gt;Snowball&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;If copying files is slow: this is due to encryption overhead when copying files to the Snowball Edge device. Open multiple sessions to the Snowball Edge device and initiate parallel copy jobs to improve the overall copying throughput.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;storage-gateway&quot;&gt;Storage Gateway&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;In the &lt;strong&gt;cached mode&lt;/strong&gt;, your primary data is written to S3, while retaining your frequently accessed data locally in a cache for low-latency access.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;stored mode&lt;/strong&gt;, your primary data is stored locally and your entire dataset is available for low-latency access while asynchronously backed up to AWS.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;vpc&quot;&gt;VPC&lt;/h3&gt;
&lt;h4 id=&quot;nat-gateway&quot;&gt;NAT Gateway&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;NAT Gateway do not support IPv6
&lt;ul&gt;
&lt;li&gt;same for NAT instances&lt;/li&gt;
&lt;li&gt;If you need IPv6 traffic use an egress-only internet Gateway&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;You’d generally prefer a NAT Gataway over a NAT instance because
&lt;ul&gt;
&lt;li&gt;Gateway is a managed service&lt;/li&gt;
&lt;li&gt;Highly available&lt;/li&gt;
&lt;li&gt;Scales automatically&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;But you might prefer a NAT instance when:
&lt;ul&gt;
&lt;li&gt;Need to save money for a small workload that doesn’t require High Availability&lt;/li&gt;
&lt;li&gt;You need to fine tune security groups&lt;/li&gt;
&lt;li&gt;You want the ability to detach your Elastic IP&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;allow-a-vpc-to-resolve-using-on-premise-dns&quot;&gt;Allow a VPC to resolve using on-premise DNS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Configure a DHCP Option Set to issue your on-prem DNS IP to VPC clients.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;egress-only-internet-gateway&quot;&gt;Egress-Only Internet Gateway&lt;/h4&gt;
&lt;p&gt;The purpose of an “Egress-Only Internet Gateway” is to allow IPv6 based traffic within a VPC to access the Internet, whilst denying any Internet based resources the possibility of initiating a connection back into the VPC.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Allows VPC based IPv6 traffic to communicate to the Internet&lt;/li&gt;
&lt;li&gt;Prevents IPv6 based Internet resources initiating a connection into a VPC&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;default-dns-address-for-dhcp&quot;&gt;Default DNS address for DHCP&lt;/h4&gt;
&lt;p&gt;For default settings the DHCP address of a subnet is always the base CIDR of the subnet plus 2.&lt;/p&gt;
&lt;p&gt;E.g. if the base is &lt;code&gt;10.0.0.0/16&lt;/code&gt; the DHCP address is &lt;code&gt;10.0.0.2&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&quot;waf&quot;&gt;WAF&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Web Application Firewall&lt;/li&gt;
&lt;li&gt;Level 7 firewall that can be used to block web traffic&lt;/li&gt;
&lt;li&gt;Can be used with ALB and CloudFront distributions&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;tips&quot;&gt;Tips&lt;/h2&gt;
&lt;p&gt;Here are some things that I picked up while doing the practice exams and that can help to analyse questions and identify the correct answer(s):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;“Scalable and cost effective”&lt;/em&gt; storage is always a hint to pick DynamoDB, not RDS! Aurora could also be an option, but only if the question explicitly states &lt;em&gt;“Relational Database”&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Everytime you encounter “Slow connection” and “migration from on-premise to the cloud” expect Snowball to be one of the answers.&lt;/li&gt;
&lt;li&gt;Never pick reserved instances with workloads that are limited in time.&lt;/li&gt;
&lt;li&gt;Oracle RAC is not supported by RDS: all questions mentioning RAC will probably require you to spin up Oracle RAC in a dedicated EC2 instance.&lt;/li&gt;
&lt;li&gt;When TCO (Total Cost of Ownership) is mentioned, the answer is generally requiring you to use AWS Application Discovery Service.&lt;/li&gt;
&lt;li&gt;“Dedicated” vs “Reserved” instances. Sometimes used in the wrong way in the answers. Make sure you understand the difference so you can easily spot choices that can be easily removed. Dedicated: instances that are not shared with other AWS customers; Reserved: instances that you reserved (paid for) in advance.&lt;/li&gt;
&lt;li&gt;“Memcache” vs “Redis” (ElastiCache), always pick Redis, except when it’s explicitly requested that the caching layer needs to be multithreaded.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I want to give a huge shout out to &lt;a href=&quot;https://fourtheorem.com&quot;&gt;fourTheorem&lt;/a&gt; for supporting me in this endeavor and giving me time to study and access to paid material! ❤️ Also, thanks a million to my colleague &lt;a href=&quot;https://github.com/adminy&quot;&gt;Marin&lt;/a&gt; for reviewing this article and suggesting a few improvements! 🙌&lt;/p&gt;
&lt;p&gt;This concludes what I had to share. Please do let me know if you found this material interesting and useful.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/loige&quot;&gt;Give me a nudge on Twitter&lt;/a&gt; (my DMs are ope) if you are preparing for the exam and there are topics that you want to discuss or if you have questions you want to ask. Chances are I won’t have great answers for you, but we can still have fun chatting about AWS and cloud topic! 🙃&lt;/p&gt;
&lt;p&gt;I wish you the very best for your exam!&lt;/p&gt;
&lt;p&gt;See you on the next post!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/aws-solution-architect-professional-exam-notes-tips.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/aws-solution-architect-professional-exam-notes-tips.png" width="1200" height="630"/></media:content><category>aws</category><author>Luciano Mammino</author><comments>https://loige.co/aws-solution-architect-professional-exam-notes-tips/#comments</comments><enclosure url="https://loige.co/og/aws-solution-architect-professional-exam-notes-tips.png" length="0" type="image/png"/></item><item><title>2021 - A year in review</title><link>https://loige.co/2021-a-year-in-review/</link><guid isPermaLink="true">https://loige.co/2021-a-year-in-review/</guid><description>In 2021 I joined fourTheorem, became a Microsoft MVP, spoke at many conferences, learned Rust, contributed to open source and much more. I reflect on my professional achievements over the past year.</description><pubDate>Wed, 02 Feb 2022 20:25:00 GMT</pubDate><content:encoded>&lt;p&gt;A post where I reflect on my professional life in 2021 as a look ahead for what to expect in 2022.&lt;/p&gt;
&lt;p&gt;As usual, let me tell you that I write this kind of posts for myself and I don’t expect other people to be able to read this and be engaged. So, if you really feel like you want to venture forward and have a peek on my 2021, well, I am flattered… but make sure to grab a coffee, because this might get a little (just a little…) boring!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;boring stuff ahead&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;200&quot; height=&quot;150&quot; src=&quot;https://loige.co/_astro/boring-yawn-baby.CssTlhgk_xPmIg.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Yes, this GIF is probably the least boring element of the whole article! 😍&lt;/p&gt;
&lt;h2 id=&quot;joining-fourtheorem&quot;&gt;Joining fourTheorem&lt;/h2&gt;
&lt;p&gt;The biggest highlight of my 2021 is that in February I joined &lt;a href=&quot;https://www.fourtheorem.com/&quot;&gt;fourTheorem&lt;/a&gt; as a &lt;strong&gt;Senior Architect&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.fourtheorem.com/&quot;&gt;&lt;img alt=&quot;fourTheorem, business focused technologist that deliver specialised in AWS consulting&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1052&quot; height=&quot;473&quot; src=&quot;https://loige.co/_astro/fourtheorem-aws-consultants.V3i7sJic_Z2mzrN1.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you never heard about fourTheorem, here’s what you need to know. It’s a great service company founded by &lt;a href=&quot;https://www.linkedin.com/in/peterelger&quot;&gt;Peter Elger&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/fiona-mc-kenna-174172a2&quot;&gt;Fiona McKenna&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/eoins&quot;&gt;Eoin Shanaghy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The company, while still relatively new and small, has a large amount of expertise in &lt;a href=&quot;/tag/serverless&quot;&gt;serverless&lt;/a&gt;, &lt;strong&gt;platform modernisation&lt;/strong&gt; and &lt;a href=&quot;https://www.manning.com/books/ai-as-a-service&quot;&gt;AI as a service&lt;/a&gt;. Most importantly, fourTheorem has a huge amount of experience with &lt;a href=&quot;/tag/aws&quot;&gt;AWS&lt;/a&gt;. We are &lt;strong&gt;AWS Consulting Partners&lt;/strong&gt; and we have been helping small and big customers to transition to the cloud and get the best out of it!&lt;/p&gt;
&lt;p&gt;I have to admit I was initially skeptical about being able to work with a company that is not focused on delivering one single product but that is mainly helping many other companies to do that. In the past I rarely had a great experience when being on the other side and dealing with other service companies.&lt;/p&gt;
&lt;p&gt;But I was immediately reassured by the fact that Eoin and Peter are not just two amazingly good technical founders, but they also have an impressive track record working with companies of all sizes: from small startups to big corporations. Together with Fiona, the founding trio has a very inspiring vision for what they want the company to become.&lt;/p&gt;
&lt;p&gt;I immediately had the feeling that they wanted to build something very different from the other service companies out there. This feeling became apparent pretty quickly just after the first week, when I saw how they managed to embed their team into the customer’s team and work together in all the phases of the product. FourTheorem can literally be an extension of a team, bringing not just people and technology skills, but also a very practical and agile approach to software delivery.&lt;/p&gt;
&lt;p&gt;And after almost a year, I cannot hide the fact that I have never been happier in a technical position. I can work in an environment with fantastic colleagues, an amazing culture, in a very supportive environment where I am learning a ton. Most importantly, I feel like there is a lot of potential and that I can have an impact.&lt;/p&gt;
&lt;p&gt;Finally I get a significant amount of “work time” to invest in content creation, open source and to study (new tech, certifications, etc.). This is something that I consider integral part of my professional career path and it’s great to see that it is valued and supported!&lt;/p&gt;
&lt;p&gt;Mandatory disclaimer: we are always hiring, so if you are interested feel free to reach out to me on &lt;a href=&quot;https://twitter.com/loige&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://www.linkedin.com/in/lucianomammino/&quot;&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also… if you are looking for help for your cloud migration or to improve your AWS deployments, don’t be shy, &lt;a href=&quot;https://www.fourtheorem.com/contact&quot;&gt;let’s have a coffee-chat&lt;/a&gt;! 😉&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Be not afraid of discomfort. If you can’t put yourself in a situation where you are uncomfortable, then you will never grow. You will never change. You’ll never learn.&lt;/p&gt;
&lt;p&gt;— Jason Reynolds&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;becoming-an-mvp&quot;&gt;Becoming an MVP&lt;/h2&gt;
&lt;p&gt;In 2021 I was awarded the title of &lt;strong&gt;Most Valuable Professional&lt;/strong&gt; (&lt;a href=&quot;https://mvp.microsoft.com/en-us/&quot;&gt;MVP&lt;/a&gt;) for &lt;strong&gt;Developer Technologies&lt;/strong&gt; by &lt;strong&gt;Microsoft&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Luciano Mammino, Microsoft MVP - Most Valuable Professional for Developer Technologies&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;540&quot; height=&quot;657&quot; src=&quot;https://loige.co/_astro/luciano-mammino-mvp-microsoft-most-valuable-professional.R2bNgMUZ_Z8HKGN.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;The MVP program awards &lt;em&gt;exceptional community leadership&lt;/em&gt; across the world of tech.&lt;/p&gt;
&lt;p&gt;Apparently, to become an MVP, you need to do the following 4 things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Demonstrate community leadership and influence&lt;/li&gt;
&lt;li&gt;Be a technical expert&lt;/li&gt;
&lt;li&gt;Be a great advocate for the community&lt;/li&gt;
&lt;li&gt;Contribute to the success of our products&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If nothing else, this makes me think that the community is getting some value from the work I am doing and this can only push me to do more!&lt;/p&gt;
&lt;p&gt;I am really glad that the amazing &lt;a href=&quot;https://www.linkedin.com/in/francescosciuti&quot;&gt;Francesco Sciuti&lt;/a&gt; (who nominated me) thinks that I have done such a good job to deserve the award and thanks Microsoft for agreeing with him! ❤️&lt;/p&gt;
&lt;p&gt;One funny thing is that, during the due diligence phase, Microsoft makes you fill a big form to list all the things you think had the most impact on the community. Having written posts like this in the last few years helped me a lot to come up with a consistent list. Maybe it wasn’t such a bad idea to write these posts after all…&lt;/p&gt;
&lt;p&gt;If you are curious, you can also &lt;a href=&quot;https://mvp.microsoft.com/en-us/PublicProfile/5004232?fullName=Luciano%20Mammino&quot;&gt;check out my profile&lt;/a&gt; on the MVP network.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It’s not like after winning an award, your job is done and you can relax. You still have to work hard.&lt;/p&gt;
&lt;p&gt;— Diljit Dosanjh&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;public-speaking&quot;&gt;Public speaking&lt;/h2&gt;
&lt;p&gt;In 2021 I had the pleasure (and the immense luck) to be able to do quite a lot of publick speaking.&lt;/p&gt;
&lt;p&gt;It’s hard to pick a favourite but, being such a fan of Node.js, there’s one that I am particularly proud about: &lt;a href=&quot;https://www.nodeconfremote.com/&quot;&gt;NodeConf Remote&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=uTzBHPpMEhA&quot;&gt;&lt;img alt=&quot;Luciano Mammino presenting the talk &amp;quot;Finding a lost song with Node.js &amp;amp;#x26; async iterators&amp;quot; at Nodeconf remote 2021&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;600&quot; height=&quot;337&quot; src=&quot;https://loige.co/_astro/luciano-mammino-speaking-at-nodeconf-eu-2021-nodejs.BRxKvjXb_1OFrGa.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here’s the full list of talks, workshops and interviews that I delievered in 2021:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An opinionated intro to Node.js - Devrupt Hospitality Hackaton (&lt;a href=&quot;https://loige.link/devrupt-node&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;From Node.js to Design Patterns - Codemotion DevCast (&lt;a href=&quot;https://loige.link/devrupt-node&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Let’s play with Node.js streams (workshop) - CityJS (&lt;a href=&quot;https://loige.link/streams-city&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Let’s play with Node.js streams (workshop) - Codemotion (&lt;a href=&quot;https://loige.link/streams-cm&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;A podcast about Node.js with Vishwas Narayan (&lt;a href=&quot;https://www.youtube.com/watch?v=Wmu53Xos7Ug&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;My first Rust crate: jwtinfo (lightning talk) - Rust Dublin Meetup (&lt;a href=&quot;https://loige.link/rust-jwt&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://youtu.be/FuqLMqGcEE4&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Chats and career advice with Superheroes Valley&lt;/li&gt;
&lt;li&gt;Live stream with Fabio Biondi - Node.js Streams (&lt;a href=&quot;https://www.youtube.com/watch?v=hOHTQgOtg3w&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Finding a lost song with Node.js &amp;#x26; async iterators - Node.js Dublin meetup (&lt;a href=&quot;https://loige.link/async-it&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Interview with Gitbar podcast (&lt;a href=&quot;https://www.gitbar.it/episodes/ep-73-js-con-luciano-mammino_2&quot;&gt;Podcast Episode&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Javascript: repetita iuvant - Codemotion DevCast (&lt;a href=&quot;https://loige.link/devcast2&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Teach Kelvin Your Thing: JavaScript Async iterators (&lt;a href=&quot;https://www.youtube.com/watch?v=l2CA9FtW1Pw&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;An intro to the JAMStack &amp;#x26; Eleventy - Codemotion (&lt;a href=&quot;https://loige.link/11ty-jam&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://talks.codemotion.com/an-intro-to-the-jamstack--eleventy&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Reiterating JavaScript and Node.js iterators - RomaJS (&lt;a href=&quot;https://loige.link/iter&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=2jzN7Ns5jeQ&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;A chat with Luca Brunello (&lt;a href=&quot;https://www.youtube.com/watch?v=-M6zWYVwuz4&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;AWS Observability without the pain (&lt;a href=&quot;https://fth.link/o11y-no-pain&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Finding a lost song with Node.js &amp;#x26; async iterators - Sailsconf (&lt;a href=&quot;https://loige.link/iter-sails&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=yott9nYsEZ8&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;How to send gzipped requests with boto3 (&lt;a href=&quot;https://loige.link/gzip-boto3&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Quality questions with the NoobDev podcast (&lt;a href=&quot;https://anchor.fm/noobdevtalks/episodes/Episode-11---Quality-Questions-with-Luciano-M-e1817pb/a-a6jrkh1&quot;&gt;Podcast Episode&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Finding a lost song with Node.js &amp;#x26; async iterators - EnterJS (&lt;a href=&quot;https://loige.link/enter-iterators&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;How to Train a Computer Vision Model - Sparkd.ai on Twitch (&lt;a href=&quot;https://docs.google.com/presentation/d/151ts-Rw_EG0-4zBk-kGRniX2ImoCga8y28Qtayj78YI/edit?usp=sharing&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://youtu.be/urCY_2-n2r0&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Finding a lost song with Node.js &amp;#x26; async iterators - NodeConf Remote (&lt;a href=&quot;https://loige.link/nodeconf-iter&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://youtu.be/uTzBHPpMEhA&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Semplificare l’observability per progetti Serverless su AWS - Cloud Day conference (&lt;a href=&quot;https://loige.link/simple-obs&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;AWS Observability made simple - AWS Community Day Ireland (&lt;a href=&quot;https://fth.link/o11y-simple&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Authors and Architects (Panel) - AWS Community Day Ireland&lt;/li&gt;
&lt;li&gt;Serverless, Devops &amp;#x26; Developer Tools (Panel) - AWS Community Day Ireland&lt;/li&gt;
&lt;li&gt;Node.js, Rust &amp;#x26; Cloud Architectures (interview) - Inference Podcast (&lt;a href=&quot;https://www.youtube.com/watch?v=oCjps_uv7P4&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;A look inside the European Covid Green Pass - Codemotion (&lt;a href=&quot;https://loige.link/green&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://talks.codemotion.com/a-look-inside-the-european-covid-green-p?playlist=online-tech-conference-2021---english-ed&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Node.js scalability tips - Azure Developer Community Meetup (&lt;a href=&quot;https://loige.link/node-adc&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I am stopping counting them (more on this later), but just looking at the length of the list this year feels like a personal record from this the public speaking angle.&lt;/p&gt;
&lt;p&gt;If you are curious to see all my talks, I keep collecting them in the &lt;a href=&quot;/speaking&quot;&gt;speaking section&lt;/a&gt; of this blog.&lt;/p&gt;
&lt;p&gt;After 2 years of remote speaking I have to admit that, even if I like to be able to speak to people all around the world with just a click, I do miss meeting people face to face. It feels like I haven’t been able to form the same level of relationship I had the fortune to form in the previous years where I was able to meet attendees, organisers and other speakers in person.&lt;/p&gt;
&lt;p&gt;Hopefully this year it will be safe to do a few events in person again. 🤞&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Sharing is good, and with digital technology, sharing is easy.&lt;/p&gt;
&lt;p&gt;— Richard Stallman&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;aws-bites&quot;&gt;AWS Bites&lt;/h2&gt;
&lt;p&gt;A new activity I started this year is &lt;a href=&quot;https://awsbites.com&quot;&gt;AWS Bites podcast&lt;/a&gt;. AWS Bites was born from an idea of &lt;a href=&quot;https://twitter.com/eoins&quot;&gt;Eoin Shanaghy&lt;/a&gt;. It’s essentially a podcast series where, in every episode, we try to answer an interesting questions about AWS.&lt;/p&gt;
&lt;p&gt;If you want to have a feeling for it, this one is probably one of my favourite episodes so far:&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em; margin-top: 2em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://www.youtube.com/embed/qf0CuUOtPEI&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Some other episodes I am really proud about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=WF701W3akKw&amp;#x26;list=PLAWXFhe0N1vKrKPvgO30WJxhXoYO0-Aaq&amp;#x26;index=19&quot;&gt;19. Is the serverless DX still immature?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=jjyNTNQdW2s&amp;#x26;list=PLAWXFhe0N1vKrKPvgO30WJxhXoYO0-Aaq&amp;#x26;index=16&quot;&gt;16. What are the pros and cons of CDK?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=a57pXpcA_Bs&amp;#x26;list=PLAWXFhe0N1vKrKPvgO30WJxhXoYO0-Aaq&amp;#x26;index=10&quot;&gt;10. Lambda or Fargate for containers?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=UiXAKbPSVsE&amp;#x26;list=PLAWXFhe0N1vKrKPvgO30WJxhXoYO0-Aaq&amp;#x26;index=1&amp;#x26;t=1s&quot;&gt;01. When should I use serverless?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The goal for this podcast is to be able to share our AWS expertise in a simple and easy to digest format.&lt;/p&gt;
&lt;p&gt;Even if we have recorded more than 20 episode it still feels like we are at the beginning of the journey and we are often trying to revisit and refine the format and the delivery. So, if you have any suggestion please let us know!&lt;/p&gt;
&lt;p&gt;Also, if you like the format don’t forget to subscribe &lt;a href=&quot;https://www.youtube.com/AWSBites&quot;&gt;AWS Bites YouTube channel&lt;/a&gt;. 🙏&lt;/p&gt;
&lt;p&gt;If you prefer the audio-only version, you can check out &lt;a href=&quot;https://anchor.fm/aws-bites&quot;&gt;AWS Bites podcast on Anchor.fm&lt;/a&gt;, which also makes it available on &lt;a href=&quot;https://open.spotify.com/show/3Lh7PzqBFV6yt5WsTAmO5q&quot;&gt;Spotify&lt;/a&gt;, &lt;a href=&quot;https://podcasts.apple.com/us/podcast/aws-bites/id1585489017&quot;&gt;Apple Podcasts&lt;/a&gt;, &lt;a href=&quot;https://www.google.com/podcasts?feed=aHR0cHM6Ly9hbmNob3IuZm0vcy82YTMzMTJhMC9wb2RjYXN0L3Jzcw==&quot;&gt;Google Podcasts&lt;/a&gt; and others!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The art and science of asking questions is the source of all knowledge.&lt;/p&gt;
&lt;p&gt;— Thomas Berger&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;advent-of-code-in-rust-twitch-live-streams&quot;&gt;Advent of Code in Rust (Twitch live streams)&lt;/h2&gt;
&lt;p&gt;On my personal quest to learn &lt;a href=&quot;/tag/rust&quot;&gt;Rust&lt;/a&gt;, I decided to start a &lt;a href=&quot;https://www.twitch.tv/loige&quot;&gt;Twitch channel&lt;/a&gt; where I could live-stream my efforts. And the best thing ever is that I haven’t been alone in this effort because I have been joined by my good friends &lt;a href=&quot;https://twitter.com/gbinside&quot;&gt;Roberto&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/88_eugen&quot;&gt;Eugen&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Together we have been live-streaming our attempts at cracking &lt;a href=&quot;https://adventofcode.com/&quot;&gt;Advent of Code&lt;/a&gt; using Rust. It has been a great challenge and a very good way to consistently have something to hack in Rust.&lt;/p&gt;
&lt;p&gt;We are posting all the recordings on &lt;a href=&quot;https://www.youtube.com/channel/UCL0w2IAjTBx3NNka-l7InPw&quot;&gt;YouTube&lt;/a&gt;, so if you are really curious to see us stumbling against the Rust borrow checker or scratching our head with some interesting algorithm you can do that (even at 2x speed).&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em; margin-top: 2em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://www.youtube.com/embed/A10n3rO9ems&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Last year we managed to complete all the exercises from year 2020 of Advent of Code. This year we are continuing our efforts at cracking the 2021 edition. We have already &lt;a href=&quot;https://github.com/lmammino/rust-advent&quot;&gt;solved most of them&lt;/a&gt;, so we might decide soon to start streaming other types of Rust adventures… Maybe some serverless AWS with Rust or building a game with Bevy… who knows!&lt;/p&gt;
&lt;p&gt;We live-stream every Monday at 6PM Dublin time.&lt;/p&gt;
&lt;p&gt;Make sure to subscribe the &lt;a href=&quot;https://www.youtube.com/channel/UCL0w2IAjTBx3NNka-l7InPw&quot;&gt;YouTube channel&lt;/a&gt; or &lt;a href=&quot;https://www.twitch.tv/loige&quot;&gt;Twitch&lt;/a&gt; if you want to learn Rust with us!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Try to learn something about everything and everything about something.&lt;/p&gt;
&lt;p&gt;— Thomas Huxley&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;nodejs-design-patterns&quot;&gt;Node.js Design Patterns&lt;/h2&gt;
&lt;p&gt;The main thing to report about &lt;a href=&quot;https://www.nodejsdesignpatterns.com/&quot;&gt;Node.js Design Patterns&lt;/a&gt; is that the book kept getting some good amount of organic love.&lt;/p&gt;
&lt;p&gt;I have been seeing &lt;a href=&quot;https://www.youtube.com/watch?v=AWISf1mNcso&quot;&gt;many&lt;/a&gt; &lt;a href=&quot;https://www.linkedin.com/feed/update/urn:li:activity:6860969046414897152?commentUrn=urn%3Ali%3Acomment%3A%28activity%3A6860969046414897152%2C6860982414454476800%29&quot;&gt;mentions&lt;/a&gt; &lt;a href=&quot;https://twitter.com/enriquezrene_ap/status/1481261086875783172&quot;&gt;online&lt;/a&gt; and even jokes!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/kevteljeur/status/1460563229487288322?t=PiphPnvZTXuZS7WVLC4-xA&amp;#x26;s=19&quot;&gt;&lt;img alt=&quot;Node.js Design patterns mock cover pretending we are thinking to swith to Rust&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;650&quot; height=&quot;771&quot; src=&quot;https://loige.co/_astro/node-js-design-patterns-joke-by-kevin.Dv55MS6D_Zi4oiy.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thanks &lt;a href=&quot;https://twitter.com/kevteljeur&quot;&gt;Kevin&lt;/a&gt; for this brilliant mockup (Kevin has even created a &lt;a href=&quot;https://twitter.com/kevteljeur/status/1465265876161159178/photo/2&quot;&gt;PHP version&lt;/a&gt;)!&lt;/p&gt;
&lt;p&gt;⚠️ For the records, &lt;strong&gt;this is a joke&lt;/strong&gt;, we are not writing a book about &lt;a href=&quot;/tag/rust&quot;&gt;Rust&lt;/a&gt; or &lt;a href=&quot;/tag/php&quot;&gt;PHP&lt;/a&gt;! 😅&lt;/p&gt;
&lt;p&gt;What’s amazing is that Node.js Design Patterns has recently surpassed &lt;a href=&quot;https://nodejsdp.link/buy&quot;&gt;100 reviews on Amazon&lt;/a&gt; and it’s still rocking positively at an average of &lt;strong&gt;4.6 stars&lt;/strong&gt;! This fills me with joy! ❤️&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.com/dp/1839214112?tag=loige09-21#customerReviews&quot;&gt;&lt;img alt=&quot;Reviews of Node.js Design Patterns as of January 2022&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;443&quot; height=&quot;405&quot; src=&quot;https://loige.co/_astro/node-js-design-patterns-amazon-reviews.DUJfngLH_1t9o8U.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you haven’t left a review for Node.js Design Patterns yet, please &lt;a href=&quot;https://www.amazon.com/dp/1839214112?tag=loige09-21#customerReviews&quot;&gt;consider doing so&lt;/a&gt;. This is one of the most effective actions you could do to help us promoting the book and tell us what we can do to make it better! 🙏&lt;/p&gt;
&lt;p&gt;A final note is that, throughout last year, we published 3 new blog articles on the blog section of the book website:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nodejsdesignpatterns.com/blog/node-js-race-conditions/&quot;&gt;Node.js race conditions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nodejsdesignpatterns.com/blog/node-js-development-with-docker-and-docker-compose/&quot;&gt;Node.js development with Docker and Docker Compose&lt;/a&gt; (huge thanks to &lt;a href=&quot;https://www.giuseppemorelli.net/&quot;&gt;Giuseppe Morelli&lt;/a&gt; for authoring this one!)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nodejsdesignpatterns.com/blog/javascript-async-iterators/&quot;&gt;JavaScript async iterators&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Go check them out if you find them interesting!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You cannot open a book without learning something.&lt;/p&gt;
&lt;p&gt;— Confucius&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;fullstack-bulletin&quot;&gt;FullStack Bulletin&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://fullstackbulletin.com/&quot;&gt;FullStack bulletin&lt;/a&gt; is a free weekly newsletter about full stack web development. I have been running this project with my dear friend &lt;a href=&quot;https://twitter.com/andreaman87&quot;&gt;Andrea Mangano&lt;/a&gt; for the last 4 years counting &lt;a href=&quot;https://us15.campaign-archive.com/home/?u=b015626aa6028495fe77c75ea&amp;#x26;id=55ace33899&quot;&gt;&lt;strong&gt;258 issues&lt;/strong&gt;&lt;/a&gt; today!&lt;/p&gt;
&lt;p&gt;The project is totally &lt;a href=&quot;https://github.com/FullStackBulletin&quot;&gt;open source&lt;/a&gt; and uses tons of automation to minimise the amount of manual work.&lt;/p&gt;
&lt;p&gt;Although we had some plans for a redesign, we didn’t manage to find the time to ship any significant change In 2021, but the newsletter kept growing organically nonetheless.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The growth of FullStack bulletin in terms of subscribers throughout 2020&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;542&quot; src=&quot;https://loige.co/_astro/fullstackbulletin-2021-growth.QrlKJZca_ZOBqRF.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;One cool thing worth mentioning is that we started to get some interest in sponsorship campaign and we managed to get 5 amazing companies to sponsor several editions of FullStack Bulletin:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Amazing companies who have sponsored FullStack Bulletin in 2021&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1073&quot; height=&quot;408&quot; src=&quot;https://loige.co/_astro/fullstack-bulletin-sponsors.CFaEk2A3_ZYqHFY.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Sponsorships help us cover the costs associated with running the newsletter (Mailchimp, domains, hosting, etc.).&lt;/p&gt;
&lt;p&gt;If you would like to support FullStack Bulletin and you have a product or an idea that you would like to expose to an audience of ~2.000 amazing full stack developers, consider &lt;a href=&quot;https://fstack.link/sponsor&quot;&gt;sponsoring&lt;/a&gt; one of the next issues.&lt;/p&gt;
&lt;p&gt;Finally, there are certainly many ways we can improve FullStack Bulletin, so if you have any suggestion, please do let us know!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;More than kisses, letters mingle souls.&lt;/p&gt;
&lt;p&gt;— John Donne&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;middy&quot;&gt;Middy&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://middy.js.org/&quot;&gt;Middy&lt;/a&gt; is a Node.js middleware framework for AWS Lambda. I have been working on this project since the early days of Lambda (even though the first public commit was made the 3rd of August 2017).&lt;/p&gt;
&lt;p&gt;With that being said, I can’t really claim anything for the success of the framework during the last couple of years. Insted all the credit goes to &lt;a href=&quot;https://github.com/willfarrell&quot;&gt;Will Farrell&lt;/a&gt;, who has been relentlessy maintaining the framework, and to the amazing community behind Middy!&lt;/p&gt;
&lt;p&gt;The reason why I wanted to mention Middy here is because last year Middy started to get a lot more traction.&lt;/p&gt;
&lt;p&gt;First of all Middy reached &lt;strong&gt;2700 GitHub stars&lt;/strong&gt; (not a crazy impressive number, but still something I can feel proud about):&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Middy reached 2700 Stars on GitHub&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;283&quot; height=&quot;74&quot; src=&quot;https://loige.co/_astro/middy-stars.D4mJ_Iqo_OVo8k.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Yeah, if you haven’t given your star to the project, what are you waiting for? 😛&lt;/p&gt;
&lt;p&gt;But let’s be fair, stars are just a bit of a vanity metric! What is cooler is that Middy is currently trending at about &lt;strong&gt;160.000 downloads/day&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmtrends.com/middy-vs-@middy/core&quot;&gt;&lt;img alt=&quot;Middy is currently trending at about 160.000 downloads per day&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1327&quot; height=&quot;550&quot; src=&quot;https://loige.co/_astro/middy-downloads-per-day.Lbr75cdd_28qMGC.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If we look at the total number of downloads per year things seems even more impressive:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://npm-stat.com/charts.html?package=%40middy%2Fcore&amp;#x26;package=middy&amp;#x26;from=2019-01-01&amp;#x26;to=2021-12-31&quot;&gt;&lt;img alt=&quot;Yearly downloads for Middy from 2019 to 2021&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;992&quot; height=&quot;561&quot; src=&quot;https://loige.co/_astro/middy-yearly-downloads-2020.DGDdggdX_1857wo.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this chart you can see that &lt;code&gt;@middy/core&lt;/code&gt; + &lt;code&gt;middy&lt;/code&gt; (legacy 0.x package) reached together about &lt;strong&gt;6 million downloads&lt;/strong&gt; in 2021!&lt;/p&gt;
&lt;p&gt;And, just to put the cherry on top of the cake, what made me really happy is that Middy started to get some interesting coverage:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lambda PowerTools for TypeScript by AWS works seamlessy with Middy and &lt;a href=&quot;https://youtu.be/tr7DZxn3qag?t=1596&quot;&gt;it the integration has even been showcased live by some AWS engineers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Middy is helping with delivering Tacos 🌮🌮. No kidding, there’s &lt;a href=&quot;https://www.youtube.com/watch?v=U5GZNt0iMZY&amp;#x26;t=2974s&quot;&gt;a re:Invent 2021 talk by Taco Bells&lt;/a&gt; mentioning Middy&lt;/li&gt;
&lt;li&gt;Serverless Stack (framework) has an entire documentation page showing &lt;a href=&quot;https://serverless-stack.com/examples/how-to-use-middy-to-validate-your-serverless-api-requests.html&quot;&gt;how to use Middy validator with Serverless Stack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Redwoodjs is &lt;a href=&quot;https://github.com/redwoodjs/redwood/issues/398&quot;&gt;considering integrating with Middy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Middy is also helping with &lt;a href=&quot;https://github.com/search?q=org%3ANortheastern-Electric-Racing+middy&amp;#x26;type=code&quot;&gt;testing formula-one style electric cars&lt;/a&gt;… Those must definitely be faster than a scooter!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While all this success fills me with happyness, I expect even greater results for this year as &lt;a href=&quot;https://github.com/middyjs/middy/issues/626&quot;&gt;version 3&lt;/a&gt; is shaping up really nicely and should come out soon!&lt;/p&gt;
&lt;p&gt;PS: Last year, Will and I were interviewed about Middy by the folks at Cooper Press: &lt;a href=&quot;https://superhighway.dev/middy-node-interview&quot;&gt;A Chat with Will Farrell &amp;#x26; Luciano Mammino of Middy&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I bought an electric scooter in sixth grade. Bankrupted me.&lt;/p&gt;
&lt;p&gt;— Zac Efron&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;pro-bono-mentorship&quot;&gt;Pro-bono mentorship&lt;/h2&gt;
&lt;p&gt;In 2021, I invested some of my spare time to help engineers landing their first job. Together with my good friend &lt;a href=&quot;https://padraigobrien.com/&quot;&gt;Padraig O’Brien&lt;/a&gt;, we helped 3 engineers to fine-tune their CV, understand how to present themselves and get ready for some coding interview.&lt;/p&gt;
&lt;p&gt;I mostly helped around preparing for the coding interview. Altough it was a lot of fun to meet eager engineer and do some pair programming with them, the most rewarding part was to actually see that they were actually able to land their first job and that this is having a very positive impact in their lives.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Feedback from one of my mentee&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;466&quot; height=&quot;118&quot; src=&quot;https://loige.co/_astro/mentorship-feedback-luciano-mammino.Bf1X0R4m_Zps4Cs.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Out of the 3 engineers I had the pleasure to mentor, 2 of them got a permanent role and 1 is working off a few interesting contract roles. Let me know if you are thinking about hiring full-time an amazing React/JavaScript developer and I’ll put you in touch with them!&lt;/p&gt;
&lt;p&gt;I’d love to keep investing 1 or 2 hours of my free time every month to continue this effort. It feels great to give something back to the community. I have learned from so many people during this year and it’s good to finally being able to carry the torch for a bit!&lt;/p&gt;
&lt;p&gt;If you are looking to land your first job in tech and you feel like you can use some help for the coding interview, give me a shout!&lt;/p&gt;
&lt;p&gt;If you are keen to getting your CV reviewed and understand how you can better present yourself, make sure to reach out to &lt;a href=&quot;https://twitter.com/PadraigOBrien&quot;&gt;Podge&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;PS: you can also check out this article I wrote last year: &lt;a href=&quot;https://loige.hashnode.dev/10-tips-to-smash-the-code-interview&quot;&gt;10 tips to smash the code interview&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Don’t judge each day by the harvest you reap but by the seeds that you plant.&lt;/p&gt;
&lt;p&gt;— Robert Louis Stevenson&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;slic-watch---easy-aws-o11y&quot;&gt;SLIC Watch - Easy AWS o11y&lt;/h2&gt;
&lt;p&gt;Last year I had the fortune and the pleasure to use some of my fourTheorem time to contribute to a very cool open source project: &lt;a href=&quot;https://github.com/fourTheorem/slic-watch&quot;&gt;SLIC Watch&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;SLIC Watch is a Serverless Framework plugin that generates for you CloudWatch dashboards and alarms for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AWS Lambda&lt;/li&gt;
&lt;li&gt;API Gateway&lt;/li&gt;
&lt;li&gt;DynamoDB&lt;/li&gt;
&lt;li&gt;Kinesis Data Streams&lt;/li&gt;
&lt;li&gt;SQS Queues&lt;/li&gt;
&lt;li&gt;Step Functions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The idea behind this project is that very often we don’t invest in providing all these observability tools just because it’s hard and time consuming to get them right.&lt;/p&gt;
&lt;p&gt;SLIC Watch tries to solve this problem by looking at all the resources in your stack and it automatically adds relevant dashboards and alarms based on common industry best practices.&lt;/p&gt;
&lt;p&gt;This way you can get a good degree of “observability coverage” with very minimal effort (and time).&lt;/p&gt;
&lt;p&gt;Of course, SLIC Watch cannot replace bespoke and fine tuned dashboards and alarms, but it’s still good in the sense that it can give you a good base that should cover 80% of your needs. This way you can focus on the 20% that matters more and that is very bespoke for your business.&lt;/p&gt;
&lt;p&gt;Just to give you a more practical example, if you defined a Lambda function in your application stack, SLIC Watch will automatically provision the following alarms for you:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Errors&lt;/li&gt;
&lt;li&gt;Throttles, as a percentage of the number of invocations&lt;/li&gt;
&lt;li&gt;Duration, as a percentage of the function’s configured timeout&lt;/li&gt;
&lt;li&gt;Invocations, disabled by default&lt;/li&gt;
&lt;li&gt;IteratorAge, for function’s triggered by an Event Source Mapping&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;SLIC Watch also generates relevant dashboards for you:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Example of Dashboards and Alarms generated for you by SLIC Watch for a Lambda function&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1293&quot; height=&quot;729&quot; src=&quot;https://loige.co/_astro/dashboards-generated-by-slic-watch-for-a-lambda-function-aws.Uh1u8b4y_ZiFOag.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;If you find this interesting, make sure to &lt;a href=&quot;https://github.com/fourTheorem/slic-watch&quot;&gt;check out the official repository&lt;/a&gt; (and while you are at it, give it a star 😛).&lt;/p&gt;
&lt;p&gt;You can also check out these slides where we present the context for SLIC Watch in a more detailed way:&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em; margin-top: 2em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://docs.google.com/presentation/d/e/2PACX-1vRZHtwsIAx9Bkae3Fp-IBvJjavIYBDy0ToJHi83upsLoCZHXWWA4aeImt5NovW8i500k52nVGU6SI_q/embed?start=false&amp;#x26;loop=false&amp;#x26;delayms=30000&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;true&quot; mozallowfullscreen=&quot;true&quot; webkitallowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;To acquire knowledge, one must study; but to acquire wisdom, one must observe.&lt;/p&gt;
&lt;p&gt;— Marilyn vos Savant&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;digital-green-certificate-covid-library-rust&quot;&gt;Digital Green Certificate, Covid Library (Rust)&lt;/h2&gt;
&lt;p&gt;In June last year I got curious about the QRCodes used as part of the &lt;a href=&quot;https://github.com/ehn-dcc-development&quot;&gt;Digital Green Certificate program&lt;/a&gt; (a.k.a. &lt;em&gt;DGC&lt;/em&gt; or &lt;em&gt;DCC&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;The specification allows to encapsulate certified proof of Covid vaccination, Covid test or Covid recovery within a QRCode.&lt;/p&gt;
&lt;p&gt;I have been thinkering with the idea of using QRCodes with a digital signature in the retail world (tickets, certified coupon codes, etc.) so I was extremely curious to learn more about this project and see how they implemented the certification.&lt;/p&gt;
&lt;p&gt;As part of this research I ended up creating a &lt;a href=&quot;https://github.com/rust-italia/dgc&quot;&gt;&lt;em&gt;decoder&lt;/em&gt; library&lt;/a&gt; in &lt;a href=&quot;/tag/rust&quot;&gt;Rust&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;DGC rust library logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;153&quot; height=&quot;153&quot; src=&quot;https://loige.co/_astro/dgc-rust-logo.DVmAS6HP_Z2k2HiC.svg&quot; &gt;&lt;/p&gt;
&lt;p&gt;This library allows you to be able to read all the information encoded within the QRCode and to verify the autenticity of the certificate by checking its digital signature.&lt;/p&gt;
&lt;p&gt;It was an extremely interesting project where I got to learn a bunch of new things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/draft-faltstrom-base45/&quot;&gt;Base45 encoding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc7049&quot;&gt;CBOR encoding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc8152&quot;&gt;COSE&lt;/a&gt; and &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc8392&quot;&gt;CWT&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;…and I also reinforced a bit my understanding of cryptography and compression.&lt;/p&gt;
&lt;p&gt;The best part is that this project somehow got the attention of the (very active) &lt;a href=&quot;https://github.com/rust-italia&quot;&gt;Rust Italia&lt;/a&gt; group, which helped me a lot to refine the library and to build new features.&lt;/p&gt;
&lt;p&gt;This was amazing because it has been a great opportunity to learn from more experienced Rust developers and learn how to make a “production-ready” library. Thank you Rust Italia! ❤️&lt;/p&gt;
&lt;p&gt;I had condensed my learning in a Codemotion talk: &lt;a href=&quot;https://slides.com/lucianomammino/a-look-inside-the-european-covid-green-pass&quot;&gt;A look inside the
European Covid Green Certificate&lt;/a&gt;:&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em; margin-top: 2em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://slides.com/lucianomammino/a-look-inside-the-european-covid-green-pass/embed&quot; title=&quot;A look inside the European Covid Green Certificate&quot; scrolling=&quot;no&quot; frameborder=&quot;0&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;If this topic is something that interests you, I will be delivering the same talk again at &lt;a href=&quot;https://www.meetup.com/Rust-Dublin/events/283613610/&quot;&gt;Rust Dublin Meetup&lt;/a&gt;, this month!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When solving problems, dig at the roots instead of just hacking at the leaves.&lt;/p&gt;
&lt;p&gt;— Anthony J. D’Angelo&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;articles&quot;&gt;Articles&lt;/h2&gt;
&lt;p&gt;In addition to the articles already mentioned for the Node.js Design Patterns blog, I managed to write a few more articles during 2021.&lt;/p&gt;
&lt;p&gt;Here’s the full (boring) list of the ones published in this blog:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/where-to-go-to-learn-rust-in-2021&quot;&gt;Where to go to learn Rust in 2021&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/rust-shenanigans-return-type-polymorphism&quot;&gt;Rust shenanigans: return type polymorphism&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/how-to-to-string-in-rust&quot;&gt;How to to_string in Rust&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/how-to-send-gzipped-requests-with-boto3&quot;&gt;How to send gzipped requests with boto3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/provision-ubuntu-ec2-with-cdk&quot;&gt;Provision an Ubuntu-based EC2 instance with CDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/create-resources-conditionally-with-cdk&quot;&gt;Create resources conditionally with CDK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In retrospective, it’s interesting to see a good mix of &lt;a href=&quot;/tag/rust&quot;&gt;Rust&lt;/a&gt; and &lt;a href=&quot;/tag/aws&quot;&gt;AWS&lt;/a&gt; articles. I think this reflects well where my learnings have been focused throughout the year.&lt;/p&gt;
&lt;p&gt;I also ended up publishing a few articles outside this blog:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://buddy.works/tutorials/aws-lambda-ci-with-buddy&quot;&gt;AWS Lambda CI with Buddy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.hashnode.dev/configure-eslint-and-standardjs&quot;&gt;Configure ESlint and StandardJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/pulse/easy-serverless-observability-aws-slic-watch-luciano-mammino/&quot;&gt;Easy Serverless observability on AWS with SLIC Watch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.hashnode.dev/10-tips-to-smash-the-code-interview&quot;&gt;10 tips to smash the code interview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.hashnode.dev/your-lambdas-are-failing-and-you-dont-even-know&quot;&gt;Your Lambdas are failing and you don’t even know!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s have a quick look at some stats for this blog:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Top 10 pages at loige.co by page views for 2021&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;938&quot; height=&quot;443&quot; src=&quot;https://loige.co/_astro/loige-co-top-content-by-views-2021.BALGvBK9_4URgS.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;It’s interesting to see a mix of new and old articles, But other than that the figures in terms of total number of page views are not to far off from last year (about 70k pageviews).&lt;/p&gt;
&lt;p&gt;If we look at acquisition channels, the figure does not change too much from last year:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Top acquisition channels for loige.co in 2021&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;562&quot; height=&quot;762&quot; src=&quot;https://loige.co/_astro/loige-co-acquisition-channels-2021.BG7VDfHH_Z12CtPw.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;The majority (more than half) of the readers came from organic search. This is probably because I have a large chunk of articles in the long time still driving a lot of traffic and hopefully because of some SEO.&lt;/p&gt;
&lt;p&gt;But, if I have to be honest, I am not particularly interested in doing an in-depth analysis and trying to figure out how to squeeze more traffic from search engines.&lt;/p&gt;
&lt;p&gt;I should probably focus more on figuring out what topics are the most interesting for my audience and make sure I have a steady line of content to target those.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Whether you’re keeping a journal or writing as a meditation, it’s the same thing. What’s important is you’re having a relationship with your mind.&lt;/p&gt;
&lt;p&gt;— Natalie Goldberg&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;open-source&quot;&gt;Open Source&lt;/h2&gt;
&lt;p&gt;Every year I reported here a list with every single repo I contributed to. It’s honestly a waste of time (I am finally admitting that), so let me just summarise the ones that I think are more meaningful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/scrobbles&quot;&gt;&lt;code&gt;scrobbles&lt;/code&gt;&lt;/a&gt; is a &lt;a href=&quot;/tag/node-js&quot;&gt;Node.js&lt;/a&gt; library that allows you to fetch your “scrobbles” (songs you have been listening to) from Last.fm.&lt;/li&gt;
&lt;li&gt;I have created a &lt;a href=&quot;/tag/node-js&quot;&gt;Node.js&lt;/a&gt; Streams workshop that you can avail for free: &lt;a href=&quot;https://github.com/lmammino/streams-workshop&quot;&gt;&lt;code&gt;lmammino/streams-workshop&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I created the repo &lt;a href=&quot;https://github.com/lmammino/async-iteration-http-requests&quot;&gt;&lt;code&gt;lmammino/async-iteration-http-requests&lt;/code&gt;&lt;/a&gt;, where i thinker with the idea of using async iterators to handle incoming requests in a &lt;a href=&quot;/tag/node-js&quot;&gt;Node.js&lt;/a&gt; web server. This is something that Deno suggests as standard way build web servers. This experiment sparked a bunch of interesting conversations and I ultimately think this might be a dangerous practice.&lt;/li&gt;
&lt;li&gt;I created a repo with all my examples from the talk “Finding a lost song with &lt;a href=&quot;/tag/node-js&quot;&gt;Node.js&lt;/a&gt; and async iterators”: &lt;a href=&quot;https://github.com/lmammino/node-async-iterators-talk-examples&quot;&gt;&lt;code&gt;lmammino/node-async-iterators-talk-examples&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;I created the repo &lt;a href=&quot;https://github.com/lmammino/javascript-iteration-protocols&quot;&gt;&lt;code&gt;lmammino/javascript-iteration-protocols&lt;/code&gt;&lt;/a&gt; to show many different ways that you can use to do iteration in JavaScript and &lt;a href=&quot;/tag/node-js&quot;&gt;Node.js&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;As part of my research for DGC, I ended playing with several &lt;a href=&quot;/tag/rust&quot;&gt;Rust&lt;/a&gt; libraries for handling CBOR and eventually I contribured to my favourite one: &lt;a href=&quot;https://github.com/enarx/ciborium&quot;&gt;&lt;code&gt;enarx/ciborium&lt;/code&gt;&lt;/a&gt;. In this case I added a bunch of helper functions to simplify deserialization.&lt;/li&gt;
&lt;li&gt;I contributed to &lt;a href=&quot;https://github.com/udondan/cdk-ec2-key-pair&quot;&gt;&lt;code&gt;udondan/cdk-ec2-key-pair&lt;/code&gt;&lt;/a&gt;, a &lt;a href=&quot;/tag/cdk&quot;&gt;CDK&lt;/a&gt; construct that allows you to generate key pairs for &lt;a href=&quot;/tag/aws&quot;&gt;AWS&lt;/a&gt; EC2 instances. Small contribution to the docs, mostly redacting some examples that were a bit out of date.&lt;/li&gt;
&lt;li&gt;I started &lt;a href=&quot;https://github.com/lmammino/gmaps-static&quot;&gt;&lt;code&gt;gmaps-static&lt;/code&gt;&lt;/a&gt;, a &lt;a href=&quot;/tag/rust&quot;&gt;Rust&lt;/a&gt; crate that allows you to build URLs for &lt;a href=&quot;https://developers.google.com/maps/documentation/maps-static/overview&quot;&gt;Google Maps static pictures&lt;/a&gt;. I even &lt;a href=&quot;https://youtu.be/d_RfLXdSBl4&quot;&gt;recorded a live video&lt;/a&gt; while coding this together with &lt;a href=&quot;https://twitter.com/AlleviTommaso&quot;&gt;Tommaso Allevi&lt;/a&gt;. It is still not fully complete but it was a great experiment to learn a bunch of new interesting Rust concepts. Thank you, Tommaso! 🙌&lt;/li&gt;
&lt;li&gt;I consider playing the best way to learn something. If you can make it fun, you won’t even notice you are learning. For this reason I started &lt;a href=&quot;https://github.com/lmammino/awesome-learn-by-playing&quot;&gt;&lt;code&gt;lmammino/awesome-learn-by-playing&lt;/code&gt;&lt;/a&gt;, a repository where I tried to collect all the resources that can teach you about coding and electronics by playing games. This project gathered a bunch of contributors and many stars (thanks everyone), so it seems many people like to learn by playing. 😊&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/allwords&quot;&gt;&lt;code&gt;allwords&lt;/code&gt;&lt;/a&gt; is another &lt;a href=&quot;/tag/rust&quot;&gt;Rust&lt;/a&gt; crate that allows you to sequentially generate all the possible combinations of words over a set of characters. Could be useful for brute force attacks or fuzzy testing.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/rollz&quot;&gt;&lt;code&gt;rollz&lt;/code&gt;&lt;/a&gt; is a very simple &lt;a href=&quot;/tag/rust&quot;&gt;Rust&lt;/a&gt; crate that allows you to… roll dice! Nothing special except it was a great way to experiment with return type polymorphism and generics in Rust.&lt;/li&gt;
&lt;li&gt;I have been a pedantic nerd by &lt;a href=&quot;https://github.com/CircleCI-Public/node-orb/pull/79/files&quot;&gt;sending a PR to CircleCI&lt;/a&gt; where I renamed all their references to “NodeJS” to “&lt;a href=&quot;/tag/node-js&quot;&gt;Node.js&lt;/a&gt;”! 😅&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/microfeat&quot;&gt;&lt;code&gt;Microfeat&lt;/code&gt;&lt;/a&gt; is a super-simple and incomplete feature flag server written in &lt;a href=&quot;/tag/rust&quot;&gt;Rust&lt;/a&gt;. I wrote this during an hackaton with &lt;a href=&quot;https://twitter.com/gbinside&quot;&gt;Roberto Gambuzzi&lt;/a&gt; and it was a lot of fun to learn how to deal with http servers and websockets in Rust.&lt;/li&gt;
&lt;li&gt;I contributed to &lt;a href=&quot;https://github.com/node-formidable/formidable/&quot;&gt;&lt;code&gt;node-formidable/formidable&lt;/code&gt;&lt;/a&gt; a nice &lt;a href=&quot;/tag/node-js&quot;&gt;Node.js&lt;/a&gt; library that allows you to easily process multipart form data in streaming mode. Quite good to handle file uploads on a web server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;GitHub is something that is integral part of my daily routine. If I have an idea, 9 times out of 10, I start a repo on GitHub! If I use a library and I see something that I think can be improved I submit a PR.&lt;/p&gt;
&lt;p&gt;So I think it will come natural for me to just keep doing more open source throughout the year!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If a person has a contribution to make, they must make it in public. If learning is not made public, it is a waste.&lt;/p&gt;
&lt;p&gt;— Chaim Potok&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;moar-stuff&quot;&gt;Moar stuff&lt;/h2&gt;
&lt;p&gt;Let’s finish this post with some random stuff I did that didn’t deserve it’s own section.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I started using &lt;strong&gt;Polywork&lt;/strong&gt;, a new interesting professional social media platform focused on achievements and content creation. If you want to connect, make sure to &lt;a href=&quot;https://www.polywork.com/loige&quot;&gt;check out my PolyWork profile&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/loige/status/1486352295445123090&quot;&gt;I started using Obsidian&lt;/a&gt; to take notes and organise my thoughts and learnings. I expect it might help me a lot for content creation, but I guess we’ll revisit this guess next year!&lt;/li&gt;
&lt;li&gt;I have been attempting to learn how to type better using the touch type technique. This came from a realization that I am not comfortable with the Vim shortcuts because of the way I put my hands on the keyboard… I have been practing for a while with some online softwares, but I eventually gave up… I might try this again at some point this year!&lt;/li&gt;
&lt;li&gt;Speaking of keyboards, &lt;a href=&quot;https://twitter.com/loige/status/1442466235111940101&quot;&gt;I got a Keychron K3&lt;/a&gt; and i am loving it. One &lt;em&gt;moar&lt;/em&gt; reason to get better at typing!&lt;/li&gt;
&lt;li&gt;I haven’t restarted practicing BJJ (damn Covid!), but I have been keeping a decent running routine! Last year I run a total of &lt;strong&gt;415 km&lt;/strong&gt;. Thanks to my friend &lt;a href=&quot;https://twitter.com/lucamarchesotti&quot;&gt;Luca Marchesotti&lt;/a&gt; for holding me accountable and for often being a running partner!&lt;/li&gt;
&lt;li&gt;While running, I have been listening to audio books. I listened to a bit of everthing between educational (tech/finance) and novels. Probably my favoutire e-book of 2021 has been &lt;a href=&quot;https://www.goodreads.com/book/show/48829708-to-sleep-in-a-sea-of-stars&quot;&gt;To Sleep in a Sea of Stars by Christopher Paolini&lt;/a&gt;. Thanks to &lt;a href=&quot;https://twitter.com/RafaDelNero&quot;&gt;Rafael Del Nero&lt;/a&gt; for suggesting me to start listening to audio books while running. 🏃‍♂️💨&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;expectations-for-2022&quot;&gt;Expectations for 2022&lt;/h2&gt;
&lt;p&gt;In this section I generally used to list goals and compare with the previous years goals to see what I had achieved and what I failed at.&lt;/p&gt;
&lt;p&gt;From this year I want to try something different. Rather than thinking in terms of goals I want to establish systems that allow me to have routine where I can do things that will eventually lead me to results.&lt;/p&gt;
&lt;p&gt;I have already some routines with the Rust streams and AWS Bites podcast that help me to get better at some of the things I care about: learning Rust and getting better at AWS and cloud architectures.&lt;/p&gt;
&lt;p&gt;One single goal that I want to achieve this year is to get a new AWS certification. I am proactively studying for that, so stay tuned because I will be sharing my notes!&lt;/p&gt;
&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;In conclusion, 2021 was a crazy busy year! I did not even realise how much stuff did happen until writing this post!&lt;/p&gt;
&lt;p&gt;I feel really lucky and I can’t wait to see what I will be able to write at the end of this year… 😊&lt;/p&gt;
&lt;p&gt;Whait, WHAT? Are you still with me?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A cat saying &amp;quot;WAIT WHAT&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;260&quot; height=&quot;260&quot; src=&quot;https://loige.co/_astro/waitwhat.DVH_8DiC_13l9wz.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;That’s crazy, at this point even my mom would have closed the tab!&lt;/p&gt;
&lt;p&gt;(Mom, if you are reading this, don’t worry, I love you anyway!)&lt;/p&gt;
&lt;p&gt;What can I say? Thanks for reading all this stuff! You are my hero, so leave me a comment and let’s connect! 🥰&lt;/p&gt;
&lt;p&gt;I would love to know what were your achievements last year and what are you planning to do this year!&lt;/p&gt;
&lt;p&gt;Chat soon! 👋&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/2021-a-year-in-review.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/2021-a-year-in-review.png" width="1200" height="630"/></media:content><category>life</category><author>Luciano Mammino</author><comments>https://loige.co/2021-a-year-in-review/#comments</comments><enclosure url="https://loige.co/og/2021-a-year-in-review.png" length="0" type="image/png"/></item><item><title>The Definition of Senior: A Look at the expectations for Software Engineers</title><link>https://loige.co/the-senior-dev/</link><guid isPermaLink="true">https://loige.co/the-senior-dev/</guid><description>This article explores the multifaceted definition of a senior software engineer. It covers the technical skills like going a level deeper and having a broad understanding, as well as soft skills like communication, autonomy, business acumen, and leadership. It provides tips on how to grow, such as pair programming and content creation. The path to seniority requires dedication, perseverance and a growth mindset.</description><pubDate>Sun, 26 Mar 2023 16:30:00 GMT</pubDate><content:encoded>&lt;p&gt;In today’s fast-paced tech industry, the role of a senior software engineer has become increasingly important and something many engineers strive to be recognized as. But &lt;strong&gt;are you senior yet&lt;/strong&gt;? And &lt;strong&gt;what’s expected from you a senior&lt;/strong&gt;?&lt;/p&gt;
&lt;p&gt;The truth is that answering these questions is a very subjective matter and different people or different companies might give very different answers.&lt;/p&gt;
&lt;p&gt;In this article, I’ll try to give you my take, based on my opinion and personal experience.&lt;/p&gt;
&lt;p&gt;So let’s get to it!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This article is based on a presentation I gave last year called &lt;a href=&quot;https://loige.link/senior&quot;&gt;The senior dev, an opinionated take&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Hopefully, this article can inspire engineers to grow in their careers, help managers to hire the right people, set expectations, and support their teams.&lt;/p&gt;
&lt;h2 id=&quot;senior-yes-but-how-much&quot;&gt;Senior? Yes, but how much? 🤌&lt;/h2&gt;
&lt;p&gt;The first remark I have to make is that I am not going to focus on different levels of seniority like what it means to be a &lt;em&gt;Staff&lt;/em&gt;, a &lt;em&gt;Principal&lt;/em&gt; engineer or even an &lt;em&gt;Architect&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;What I want to focus on is what it takes to be considered and valued as a &lt;em&gt;Senior&lt;/em&gt; in the most general sense.&lt;/p&gt;
&lt;p&gt;Ok Luciano, but what heck do you mean by &lt;em&gt;being senior in the most general sense&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;The core responsibilities of a senior engineer are to &lt;strong&gt;move projects and people forward&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Some people like to call that “&lt;em&gt;being &lt;strong&gt;a force multiplier&lt;/strong&gt;&lt;/em&gt;”, which, be aware, is very different from being a &lt;em&gt;10x engineer&lt;/em&gt;. In fact, a senior engineer is first of all a &lt;strong&gt;team player&lt;/strong&gt; and not a lone hero, or a rockstar, a superstar, a magician, a grey-bearded wizard, a unicorn, or a &lt;a href=&quot;https://www.merriam-webster.com/dictionary/whatchamacallit&quot;&gt;&lt;em&gt;whatchamaccalit&lt;/em&gt;&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Easier said than done! What kind of skills, mindset, and duties are we talking about? How can an engineer effectively help to move things forward (more than a junior or a mid-level engineer can do)?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A hand typing on a dark keyboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1920&quot; height=&quot;1280&quot; src=&quot;https://loige.co/_astro/coding-on-a-keyboard-dark.PL9IQsxh_XudVd.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Photo by &lt;a href=&quot;https://unsplash.com/@quincoetzee?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Quinton Coetzee&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/xcweYgakbRo?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;h2 id=&quot;am-i-a-senior-yet&quot;&gt;Am I a senior yet?&lt;/h2&gt;
&lt;p&gt;The first myth to bust is that being senior is not necessarily a matter of how long one has been in the market!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;More time ≠ more senior&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, it definitely helps to have been around for longer. The more you do something the higher the chances that you will have faced different challenges and learned something from them!&lt;/p&gt;
&lt;p&gt;But let’s not say that you are a senior if you have &lt;em&gt;5+ years of experience&lt;/em&gt; or something like that. Unfortunately, this simple model won’t work well for many engineers!&lt;/p&gt;
&lt;p&gt;Similarly, being a senior is not a matter of age. Growing older doesn’t necessarily make you better at your job… a senior is not someone with &lt;em&gt;at least 40 years of age&lt;/em&gt;…&lt;/p&gt;
&lt;p&gt;In my career, I had the fortune to truly appreciate this.&lt;/p&gt;
&lt;p&gt;I had some very young but extremely passionate and skilled colleagues that I would definitely consider senior, and I also had &lt;em&gt;older&lt;/em&gt; colleagues with many years in the industry on their CV but their contribution to the team and the project was nearly close to zero, if not even negative! I wouldn’t have called them senior, even though, most of the time, the company recognised them as such…&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A hand coming from a hole handing an old-style alarm clock&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;932&quot; height=&quot;713&quot; src=&quot;https://loige.co/_astro/a-hand-with-an-alarm-clock.DetlpvbJ_Z10VWQt.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Photo by &lt;a href=&quot;https://unsplash.com/@lenneek?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Elena Koycheva&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/time?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-skills-do-i-need&quot;&gt;What skills do I need?&lt;/h2&gt;
&lt;p&gt;If it’s not a matter of time in the industry, what is it then?&lt;/p&gt;
&lt;p&gt;Remember, it’s all about moving your project and your team forward… and this takes some skills, so what kind of skills are we talking about?!&lt;/p&gt;
&lt;p&gt;When it comes to &lt;strong&gt;technical skills&lt;/strong&gt;, a senior software engineer is expected to have a solid foundation in programming languages, frameworks, databases, architectures, etc. However, technical skills are not the only thing that sets a senior software engineer apart. &lt;strong&gt;Soft skills&lt;/strong&gt;, such as communication, leadership, and problem-solving, are equally important.&lt;/p&gt;
&lt;p&gt;I would even argue that &lt;strong&gt;for a senior engineer, soft skills are even more important than technical skills&lt;/strong&gt;, because it’s not just about what you know, but is about how you communicate that, how you influence other people to leverage your knowledge, how you share your expertise, unblock tricky situations, and make the team more self-sufficient and productive.&lt;/p&gt;
&lt;p&gt;Communication skills are vital for senior software engineers, as they often work with cross-functional teams and communicate technical concepts to non-technical stakeholders. A senior engineer must be able to clearly articulate their ideas, listen actively, and provide constructive feedback.&lt;/p&gt;
&lt;p&gt;Leadership skills are also essential for senior software engineers, as they are often responsible for mentoring junior team members, leading project teams, and making hard technical decisions. A senior engineer must be able to inspire and motivate their team, delegate tasks effectively, and provide guidance and support when needed.&lt;/p&gt;
&lt;p&gt;Problem-solving skills are another critical skill set that senior software engineers must possess. They must be able to think critically, analyze complex problems, and find creative solutions. Senior engineers should be comfortable with ambiguity and be able to adapt quickly to changing requirements.&lt;/p&gt;
&lt;p&gt;At the end of the day, software engineering is all about solving problems!&lt;/p&gt;
&lt;p&gt;But in complex organisations, with many stakeholders coming from very different backgrounds, problems are not only technical. And problems can be badly defined and change often. So, being able to contribute to understanding what is the problem at hand, creating and sharing a vision, steering the team to take the right direction are all crucial skills that can have a massive impact.&lt;/p&gt;
&lt;p&gt;The best &lt;em&gt;technical&lt;/em&gt; solution is not always the absolute best solution for an organisation.&lt;/p&gt;
&lt;p&gt;The best solution is one that accounts for how easy it is for more junior people to contribute to it, how easy it will be to evolve it and adapt it to changing requirements, how well will it scale if the business is successful, etc.&lt;/p&gt;
&lt;p&gt;Sometimes you might have to compromise on purely technical qualities to come up with solutions that are optimal for the team and the business environment you are working on.&lt;/p&gt;
&lt;p&gt;It takes a lot more than just technical skills to see all the facets of a project and be able to come up with solutions that can fulfill all the needs.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A kid painting eggs&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1920&quot; height=&quot;1272&quot; src=&quot;https://loige.co/_astro/a-kid-painting-eggs.DBi5jpeI_Z2nad7I.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Photo by &lt;a href=&quot;https://unsplash.com/es/@kellysikkema?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Kelly Sikkema&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/k4xoACkQZiw?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;h2 id=&quot;am-i-technical-enough&quot;&gt;Am I technical enough?&lt;/h2&gt;
&lt;p&gt;Ok, ok… but I know we should really talk more about pure technical expertise!&lt;/p&gt;
&lt;p&gt;After all, given the way the tech industry works today, this is the first thing people will recognize you for!&lt;/p&gt;
&lt;p&gt;If you cannot demonstrate technical expertise you are not even going to have a chance at getting a spot for that job position you really like!&lt;/p&gt;
&lt;h3 id=&quot;t-shaped-profile&quot;&gt;T-shaped profile&lt;/h3&gt;
&lt;p&gt;As a senior software engineer, possessing technical skills that span across different domains is crucial to thriving in the ever-evolving landscape of software development. To be an effective and efficient senior software engineer, a &lt;strong&gt;T-shaped profile&lt;/strong&gt; that emphasizes mastery of one skill and proficiency in others is essential.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A road sign with a T representing the idea of a T-shaped profile&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1300&quot; height=&quot;867&quot; src=&quot;https://loige.co/_astro/t-shaped-profile.7PCk8DqZ_xHbIk.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Photo by &lt;a href=&quot;https://unsplash.com/@farber?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Jonathan Farber&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/t?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;A T-shaped profile for a software engineer refers to having expertise in a specific skill or domain (represented by the vertical stroke of the T), while also having a broad understanding of other areas (represented by the horizontal stroke). This allows individuals to contribute to a project in multiple ways while still being an expert in their primary area of focus. T-shaped profiles enable effective collaboration with team members who have different skill sets, leading to a more successful development process.&lt;/p&gt;
&lt;p&gt;A good way to build a T-shaped profile is to start by developing your vertical stroke: what will eventually become your core strength!&lt;/p&gt;
&lt;p&gt;Focus for a while on one area only. Yes, it’s better if you pick one that you really like.&lt;/p&gt;
&lt;p&gt;When you feel you mastered that particular domain try to expand your knowledge around it and start developing your horizontal stroke. Step outside your comfort zone and explore related topics. Ideally, these related topics should compound your existing knowledge and extend your ability to build products end-to-end.&lt;/p&gt;
&lt;p&gt;If you have become an expert in API development, you might want to explore databases or frontend development, because those will start to move you to a more “full-stack” profile. Similarly, you could also explore infrastructure-as-code and learn how to bring applications to production.&lt;/p&gt;
&lt;p&gt;The trick is not to try to become an expert in every one of these additional areas, but just to learn enough to be able to understand the basic ideas and collaborate effectively with people who have these areas of knowledge as their core expertise.&lt;/p&gt;
&lt;h3 id=&quot;broad-understanding&quot;&gt;Broad understanding&lt;/h3&gt;
&lt;p&gt;A broad understanding of software development is also necessary. This includes understanding the platform, architecture, code structure, testing, deployment processes, and scalability models.&lt;/p&gt;
&lt;p&gt;Moreover, a senior software engineer should comprehend the tradeoffs between different technologies and paradigms such as Monolith vs Microservices, Memory vs CPU, Highly Scalable vs Low Latency, Reusable vs Bespoke, and Complex vs Simple. Understanding the short and long-term impact of these tradeoffs is also crucial.&lt;/p&gt;
&lt;p&gt;Developing this kind of knowledge is non-trivial. It certainly requires spending a significant amount of time building products and doing so adopting different practices, programming languages, frameworks, methodologies, etc.&lt;/p&gt;
&lt;p&gt;You can broaden your knowledge only if you appreciate that every technical choice comes with its own set of tradeoffs. There will always be positive aspects and negative ones.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There’s no silver bullet in technology!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There’s no framework that you can use to build any kind of application optimally!&lt;/p&gt;
&lt;p&gt;If you have a comprehensive enough understanding of the tech landscape, you should be able to tell which set of technologies is the best to address the specific problem at hand.&lt;/p&gt;
&lt;p&gt;And, of course, it’s ok to be proven wrong, as long as you keep an open mind and you leave yourself (and the team) room for making mistakes, learning from failures, and trying alternative approaches.&lt;/p&gt;
&lt;p&gt;The path to success is rarely a straight line…&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A contorted mountain road representing an ideal path to success&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1400&quot; height=&quot;1120&quot; src=&quot;https://loige.co/_astro/the-path-to-success-is-not-a-straight-line.DFdQ5zYJ_UA1gR.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Photo by &lt;a href=&quot;https://unsplash.com/@sylvaingllm?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Sylvain Gllm&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/X4dBqRUzO2U?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;h3 id=&quot;gonna-catch-all-bugs&quot;&gt;Gonna catch all bugs!&lt;/h3&gt;
&lt;p&gt;We know that bug-free software is a myth, so I am not going to say that a senior software engineer doesn’t create bugs! Of course, they do…&lt;/p&gt;
&lt;p&gt;But it’s really important for a senior software engineer to know what can be done to reduce the number of bugs to the very minimum and to try to spot them as early as possible (possibly before the users do).&lt;/p&gt;
&lt;p&gt;Understanding and refining user stories, writing different types of tests such as unit, integration, and end-to-end tests, finding and discussing edge cases, and keeping track of technical debt are all essential skills.&lt;/p&gt;
&lt;p&gt;A senior software engineer should be able to make a big difference here and help the entire team to write better software by introducing and educating best practices about software testing.&lt;/p&gt;
&lt;p&gt;I would argue that it’s not too hard to write tests, but writing good tests it’s almost an art!&lt;/p&gt;
&lt;p&gt;To write effective tests, you need to write testable code. This means designing code that’s modular, loosely coupled, and has well-defined inputs and outputs. The better the code is designed, the easier it is to write tests for it.&lt;/p&gt;
&lt;p&gt;Your tests should be easy to read, understand, and maintain. Use descriptive names for your tests, and write tests that cover one specific feature or behavior. Avoid testing multiple features in the same test, as it can make it harder to pinpoint the source of the error.&lt;/p&gt;
&lt;p&gt;But how to learn to do all of this?!&lt;/p&gt;
&lt;p&gt;Again, practice practice practice!&lt;/p&gt;
&lt;p&gt;Start by accepting that untested code is bad code (or to the very least code that should keep you awake at night), then try to understand the specific business domain and what makes sense to be tested and how: what kind of inputs are the most representative, what kind of outputs are expected and what kind of side effects can happen.&lt;/p&gt;
&lt;p&gt;Learn the different types of tests and different testing frameworks. Finally, learn which types of test will provide the most value for the business and optimise the team workflow to focus more on those.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A ladybug climbing on a twig representing the idea of an insidious software bug&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1400&quot; height=&quot;928&quot; src=&quot;https://loige.co/_astro/a-ladybug-climing-on-a-twig-representing-the-idea-of-an-insidious-bug.D75D28wS_rdKBE.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Photo by &lt;a href=&quot;https://unsplash.com/@descampscha?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Charlotte Descamps&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/1sbVyhfdoQM?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;h3 id=&quot;promote-the-right-patterns&quot;&gt;Promote the right patterns&lt;/h3&gt;
&lt;p&gt;Having written &lt;a href=&quot;https://nodejsdesignpatterns.com/&quot;&gt;a book on design patterns&lt;/a&gt; I am certainly biased on this one…&lt;/p&gt;
&lt;p&gt;A senior software engineer should have developed some degree of &lt;em&gt;flexibility&lt;/em&gt; in different programming languages and they should understand paradigms such as OOP vs Functional, Declarative vs Imperative, and Compiled vs Interpreted. This will allow a senior software engineer to be able to solve the same problem using different tools and techniques.&lt;/p&gt;
&lt;p&gt;Similarly, a senior software engineer should understand various design patterns and best practices. This will allow them to suggest patterns that can have good long-term effects, and avoid patterns that will eventually lead to problems.&lt;/p&gt;
&lt;p&gt;Code is something that will need to evolve as the business and customer needs change, so it is important to design with evolution in mind.&lt;/p&gt;
&lt;p&gt;Patterns are not silver bullets, but just blueprints that you can decide to use to address common situations and pave the way for future improvements.&lt;/p&gt;
&lt;p&gt;Don’t try to be dogmatic and apply specific design patterns &lt;em&gt;just because you can&lt;/em&gt;, try to think about what’s the value that the specific pattern is bringing to the project and whether that value is actually important.&lt;/p&gt;
&lt;p&gt;Sometimes, &lt;em&gt;simple dummy code&lt;/em&gt; can be very effective and it can be understood and evolved easily. Some other times you do need the structure imposed by specific design patterns because that might able to make your code more testable, extendable, configurable, etc.&lt;/p&gt;
&lt;p&gt;As a senior software engineer, this is an opportunity to shine and have a significant impact during pairing sessions and code reviews!&lt;/p&gt;
&lt;h2 id=&quot;what-kind-of-soft-skills&quot;&gt;What kind of soft skills?&lt;/h2&gt;
&lt;p&gt;Now that we covered which technical skills will give you an edge in your career and allow you to be recognised as a senior engineer, let’s address the elephant in the room: soft skills.&lt;/p&gt;
&lt;p&gt;You got that interview thanks to your hardcore technical skills, but now you have a chance to really make an impression by showcasing a range of soft skills.&lt;/p&gt;
&lt;h3 id=&quot;growth-mindset&quot;&gt;Growth mindset&lt;/h3&gt;
&lt;p&gt;The mindset of a senior software engineer is just as crucial as their technical and soft skills.&lt;/p&gt;
&lt;p&gt;A senior engineer must have a &lt;strong&gt;growth mindset&lt;/strong&gt;, a willingness to learn and adapt, and a drive for continuous improvement.&lt;/p&gt;
&lt;p&gt;They should be &lt;strong&gt;comfortable with failure&lt;/strong&gt;, see it as an opportunity to learn, and &lt;strong&gt;be willing to take risks&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Always remember a senior engineer must also be a team player, not a hero. They should collaborate with their team, support their colleagues, and contribute to the team’s success.&lt;/p&gt;
&lt;h3 id=&quot;being-an-active-lever&quot;&gt;Being an active lever&lt;/h3&gt;
&lt;p&gt;A senior software engineer should have a very proactive role in an organisation. They shouldn’t just isolate themselves in a room and keep smashing their fingers against the keyboard.&lt;/p&gt;
&lt;p&gt;A senior should know when it’s time to ask hard questions and take leadership to find what they don’t know.&lt;/p&gt;
&lt;p&gt;Being able to bring a strong technical perspective to a business conversation can be very impactful and inform the business on what’s the best strategy to move things forward.&lt;/p&gt;
&lt;p&gt;To all effect, a senior should become a bridge between product and technology.&lt;/p&gt;
&lt;p&gt;This sometimes means that a senior should also &lt;strong&gt;know when to say NO&lt;/strong&gt;. No to quick and dirty solutions (that will eventually backfire hard) just to hit a deadline. No to plans that only account for building features on top of features without considering user experience and the long term stability of the product. No to arbitrary technical choices just because “&lt;em&gt;we have always done it this way and it has been fine&lt;/em&gt;”.&lt;/p&gt;
&lt;p&gt;Saying NO is easy, but also very hard. Everyone can just say NO, that’s the easy part! What’s difficult is to argue the why of that NO, propose alternative points of view, find compromises and defuse short or long term time-bombs.&lt;/p&gt;
&lt;p&gt;Being effective at this requires a fine degree of soft skills. You should know how to communicate effectively and pick your battle wisely. You cannot always say NO to everything or you’ll become recognised as a grumpy &lt;em&gt;naysayer&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;It’s more about being able to say &lt;em&gt;“NO, BUT”&lt;/em&gt; rather than just a dry &lt;em&gt;“NO”&lt;/em&gt;. And you should also be capable of doing that in front of the right people and at the right time…&lt;/p&gt;
&lt;p&gt;When done successfully, this can have a massive positive impact on the business and the team. It can lead to innovation and create new business capabilities or unique competitive advantages.&lt;/p&gt;
&lt;p&gt;This is an area of growth for me. One of those things where, when I look back at my career, I feel like I have failed at it many many times. But hopefully, I have learned something and over time I’ll get better at it…&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A kid playing Jenga as an analogy to the senior software engineer&amp;amp;#x27;s soft skills and being able to take balanced decisions for the business&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1400&quot; height=&quot;930&quot; src=&quot;https://loige.co/_astro/a-kid-playing-jenga-soft-skills-balance.DK_4QepX_ZJSIN3.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Photo by &lt;a href=&quot;https://unsplash.com/@mparzuchowski?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Michał Parzuchowski&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/geNNFqfvw48?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;h3 id=&quot;understanding-the-business&quot;&gt;Understanding the business&lt;/h3&gt;
&lt;p&gt;To be an active lever in your organisation, you need to be able to understand the business as deeply as possible.&lt;/p&gt;
&lt;p&gt;Do you know what’s the purpose of the business? What’s the long-term vision? Is there a clear strategy? What are the unique strengths and what are the weaknesses?&lt;/p&gt;
&lt;p&gt;If you can answer all these questions you are in a good position to use your technical skills to determine how technology can help the business to succeed.&lt;/p&gt;
&lt;p&gt;Only with a solid understanding of the business you will be able to pick the right battles, focus on what matters and help design systems that can serve the business well today but also be adapted to future needs.&lt;/p&gt;
&lt;h3 id=&quot;communication&quot;&gt;Communication&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;“Good communication is as stimulating as black coffee and just as hard to sleep after.”
– Anne Morrow Lindbergh&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As a software engineer, communication skills are crucial to your success. You must be able to communicate effectively with a variety of stakeholders, including other engineers, project managers, customers, and executives. This requires a wide range of communication skills, from speaking and listening to writing and presenting.&lt;/p&gt;
&lt;p&gt;Since you will need to talk with all the stakeholders, you should learn how to communicate technical concepts to non-technical stakeholders in a way that is easy to understand. It also means being able to listen to feedback and incorporate it into your work. The ability to communicate effectively with stakeholders is essential for ensuring that everyone is on the same page and that projects are completed successfully.&lt;/p&gt;
&lt;p&gt;Another important communication skill for a software engineer is the ability to explain uncertainties and propose ideas on how to address them. Software development is an inherently uncertain process, and there will always be unknowns and unforeseen challenges. As a software engineer, you need to be able to communicate these uncertainties to stakeholders in a way that is clear and concise. You also need to be able to propose ideas on how to address these uncertainties and move the project forward.&lt;/p&gt;
&lt;p&gt;In addition, software engineers must be able to talk about failures and learnings. We already covered this, but it’s important to remark that failure is an inevitable part of software development, and it is important to be transparent about failures and the lessons learned from them. This requires effective communication skills, including the ability to take ownership of mistakes and communicate them honestly to stakeholders. It also requires the ability to communicate the lessons learned from failures and incorporate them into future projects.&lt;/p&gt;
&lt;p&gt;Communication skills are also essential for writing documentation and delivering presentations. Software engineers must be able to write clear documentation that explains how their solutions work and how they should be used and operated in production. They must also be able to deliver presentations that effectively communicate technical concepts to a non-technical audience. This requires strong writing and presentation skills, as well as the ability to simplify complex topics and make them digestible for the audience.&lt;/p&gt;
&lt;p&gt;Good communication skills can open many doors and unblock complex situations. So make sure to practice them as much as possible!&lt;/p&gt;
&lt;h3 id=&quot;supporting-management&quot;&gt;Supporting management&lt;/h3&gt;
&lt;p&gt;When you are a good communicator, you become someone who can be very effective at supporting various management activities, for instance, planning and driving ceremonies. You can help with keeping track of priorities and technical debt and split complex tasks into manageable parts.&lt;/p&gt;
&lt;p&gt;You are in a unique position to understand and leverage team strengths and pull in the right people at the right time.&lt;/p&gt;
&lt;p&gt;By working closely with management, you can ensure that your work aligns with the overall business objectives and that your team’s efforts are channeled in the right direction.&lt;/p&gt;
&lt;p&gt;Planning is another crucial skill for a software engineer. This involves breaking down large projects into smaller, manageable tasks, estimating the time required for each task, and prioritizing them. Effective planning helps to ensure that projects are completed on time and within budget.&lt;/p&gt;
&lt;p&gt;Driving ceremonies such as stand-up meetings, sprint reviews, and retrospectives can provide an opportunity to share progress, identify issues, and plan for the future. As a software engineer, you need to help drive these ceremonies and ensure that they are productive and efficient.&lt;/p&gt;
&lt;p&gt;I am not suggesting that senior software engineers should replace the role of project or product managers, but instead, they should complement these roles and provide their unique technical perspective to keep objectives, plans and execution aligned with the expectations of the technical team.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A kid holding a map: an analogy of a senior software engineer being able to support management&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1400&quot; height=&quot;932&quot; src=&quot;https://loige.co/_astro/a-kid-holding-a-map.CAC8Dm8Y_Z3W6Sm.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Photo by &lt;a href=&quot;https://unsplash.com/@anniespratt?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Annie Spratt&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/kZO9xqmO_TA?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;h3 id=&quot;autonomy-and-focus-on-delivery&quot;&gt;Autonomy and focus on delivery&lt;/h3&gt;
&lt;p&gt;The last 2 soft skills I want to touch on are autonomy and a focus on delivery.&lt;/p&gt;
&lt;p&gt;Sometimes senior software engineers are in a unique position to contribute significantly to projects that require in-depth research and grind. Heavily technical projects such as the ones related to performance optimization, significant refactoring, and re-architecture. These are often projects that are quite important for the business because they can unblock innovation and bootstrap new business capabilities.&lt;/p&gt;
&lt;p&gt;In my experience, it’s not uncommon that in such projects, a single individual contributor might be well positioned to spend some amount of time focusing and achieving a significant amount of progress in a very short amount of time driving the first big chunk of the research forward.&lt;/p&gt;
&lt;p&gt;But even in these situations, it is important to avoid silos at all costs.&lt;/p&gt;
&lt;p&gt;If you are working on such a project, make sure to have regular check-ins with management and other senior colleagues to keep your progress in check, get useful feedback and share your learnings.&lt;/p&gt;
&lt;p&gt;But the ability to deliver value by working autonomously is not only useful in research projects, but it’s also a good skill to master in general.&lt;/p&gt;
&lt;p&gt;In the software industry, it is more common to work with things we don’t know than it is to work we things we know!&lt;/p&gt;
&lt;p&gt;There are always new domains to explore, new challenges to face and new tools to deal with. Therefore, it’s important to be able to learn quickly and upskill fast when needed. You shouldn’t be waiting for other people to teach you and tell you how to do certain things, you should be able to do a certain amount of progress on your own, for instance by consuming and understanding documentation and existing code.&lt;/p&gt;
&lt;p&gt;If you have broad skills already, it should almost be second nature to be able to add more to them when needed.&lt;/p&gt;
&lt;p&gt;Of course, it is OK to ask for help if you feel stuck, but it’s also important to try to do everything you can to progress on your own so you can build as much context as possible and maximise the outcome of the time spent receiving help from others.&lt;/p&gt;
&lt;p&gt;Ideally, a senior software engineer doesn’t need too much guidance. They can figure out what’s needed to move things forward by themselves and involve other people when needed.&lt;/p&gt;
&lt;p&gt;Another facet of this involves negotiating expectations and understanding what it means to be successful in the current environment. It’s good to be upfront with management and the rest of the technical team and define what individual and team success looks like. If you don’t know what’s expected from you and the rest of the team, even if you feel you are doing the right thing, you might end up not delivering the value that is expected from you; similarly, you might not be able to help your team at being successful.&lt;/p&gt;
&lt;p&gt;Building this attitude of bluntness and clarity generally keeps the mood more positive and helps with avoiding disappointments.&lt;/p&gt;
&lt;p&gt;Of course, you can’t always avoid all disappointments or failure scenarios. So when the poop hits the fan, you might be tempted to blame someone else or the system, but it’s instead more mature to ask what could have been done better and what could be done in the future to avoid similar issues from raising again.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A fan with a red background&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1400&quot; height=&quot;1083&quot; src=&quot;https://loige.co/_astro/a-fan-with-a-red-background.gmS3yBI5_Z1PSjzP.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Photo by &lt;a href=&quot;https://unsplash.com/@macroman?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Immo Wegmann&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/UMLZavpcqhw?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-can-i-grow&quot;&gt;How can I grow?&lt;/h2&gt;
&lt;p&gt;If you’re a software engineer looking to level up your skills and become a senior member of your team, you might be wondering what steps you can take to get there.&lt;/p&gt;
&lt;p&gt;Well, fear not! Here are 4 ideas (plus some extras) that I believe will help you on your journey.&lt;/p&gt;
&lt;h3 id=&quot;go-one-level-deeper&quot;&gt;Go one level deeper&lt;/h3&gt;
&lt;p&gt;First off, don’t just scratch the surface of the technologies you’re working with. Dive deeper and learn about the underlying layers.&lt;/p&gt;
&lt;p&gt;You have probably built a website or an API, but did you ever wonder how does the HTTP protocol work? Or even how does the TCP protocol works and what happens to establish a connection? Appreciating these details will give you a much richer understanding of the technologies you work with every day.&lt;/p&gt;
&lt;p&gt;Yes, it’s an endless rabbit hole if you start to dig… so how we dive deeper without getting lost and get value from it?&lt;/p&gt;
&lt;p&gt;My rule of thumb (which I have &lt;del&gt;stolen&lt;/del&gt; learned from my friend &lt;a href=&quot;https://twitter.com/gbinside&quot;&gt;Roberto&lt;/a&gt;), is to dig only 1 level down starting from the technologies you are already familiar with.&lt;/p&gt;
&lt;p&gt;Have you spent some time with &lt;em&gt;OAuth&lt;/em&gt; and &lt;em&gt;OpenID Connect&lt;/em&gt;? Well, you’ll probably want to know &lt;a href=&quot;/whats-in-a-jwt&quot;&gt;what’s inside a JWT&lt;/a&gt;. Do you understand the OAuth authorization code flow and what happens with all the redirects? Actually, do you know how signing algorithms such as RSA and HMAC work?&lt;/p&gt;
&lt;p&gt;These are all topics that you can explore to consolidate your knowledge of this particular domain. They will allow you to explore more general concepts that you might be able to re-use somewhere else.&lt;/p&gt;
&lt;p&gt;All good steps towards broadening your knowledge and becoming a more well-rounded engineer.&lt;/p&gt;
&lt;p&gt;I am often biased toward building stuff. I feel like I don’t truly understand something if I can’t build a small prototype for it. If you are like me you could try to do that as well. Can you decode a JWT token without using a library? Can you take it a step further and even implement the signature verification algorithm?&lt;/p&gt;
&lt;p&gt;Building prototypes is a great way to memorise certain concepts and truly put your understanding to the test. Of course, it takes more effort to build stuff, so choose your prototype exercises wisely: you can’t possibly re-implement 60+ years of software engineering just for the sake of learning!&lt;/p&gt;
&lt;p&gt;One funny video that I really enjoyed lately is &lt;a href=&quot;https://www.youtube.com/watch?v=H565avw-ufk&quot;&gt;The Computer Science Iceberg&lt;/a&gt;. Why do I like it so much? Because it truly illustrates this idea of descending levels of abstractions and exploring more fundamental and generic pieces of knowledge.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Just an image of an iceberg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1400&quot; height=&quot;934&quot; src=&quot;https://loige.co/_astro/an-iceberg.DzFLKlYx_1bC4kk.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Photo by &lt;a href=&quot;https://unsplash.com/@sickle?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Sergey Pesterev&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/6KCnl-EgbiU?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;h3 id=&quot;have-fun&quot;&gt;Have fun&lt;/h3&gt;
&lt;p&gt;This is one of my core beliefs: software engineering is a very challenging profession. Not because it’s harder than other professions but because things move so quickly that you can never stop learning and you’ll always have to feel behind.&lt;/p&gt;
&lt;p&gt;The one thing that could make the profession a little bit easier is a genuine passion for the subject. If you are passionate it’s going to be easier to motivate yourself to learn new things over and over!&lt;/p&gt;
&lt;p&gt;But what if I don’t know if I am passionate enough?&lt;/p&gt;
&lt;p&gt;Fair, especially if you are at the beginning of your career. There is so much in front of you that it might be scary and even discouraging.&lt;/p&gt;
&lt;p&gt;Again, my recommendation is to be biased toward building stuff. Building something will give you tangible feedback that what you are learning can actually be useful. You can build side projects to put new knowledge into practice.&lt;/p&gt;
&lt;p&gt;Also, you shouldn’t be shy to show what you built (and what you learned) to your peers and even your friends outside of work! Chances are you’ll get feedback and come up with new ideas and new things you’d like to learn and try.&lt;/p&gt;
&lt;p&gt;Even better if you realise you can apply some of these learnings at work. Maybe you can develop a new path in the company you are working for, maybe you can help with something that is currently being neglected because no one else has the time or the expertise, maybe all of this can demonstrate more value and you’ll get a promotion!&lt;/p&gt;
&lt;p&gt;When you apply this mindset of continuous learning and sharing knowledge at work, this might generate cross-pollination and you might end up with a team that has fun learning and building together.&lt;/p&gt;
&lt;p&gt;Another idea to make people gel with each other and to generate cross-pollination of ideas is to organise company &lt;strong&gt;hackatons&lt;/strong&gt; or &lt;strong&gt;free-study days&lt;/strong&gt;. These are great ways to help teams to become more passionate about what they do, explore new ideas, learn new things, and ultimately put people in a position to deliver more value in the short and the long term.&lt;/p&gt;
&lt;h3 id=&quot;pair-programming&quot;&gt;Pair programming&lt;/h3&gt;
&lt;p&gt;Pair programming is another great tool that you can leverage to give a boost to your expertise.&lt;/p&gt;
&lt;p&gt;pairing with as many people as possible within your organization is key. Even if someone is more junior than you, they can still have insights and perspectives that you may not have considered before. Pair programming gives you a platform to share ideas and learn from one another.&lt;/p&gt;
&lt;p&gt;Similarly, don’t discount the value of teaching others. Even the most senior members of your team can benefit from your knowledge and expertise. By pairing with others, you can share your skills and help everyone grow and develop.&lt;/p&gt;
&lt;p&gt;I picked up so many tricks by pairing with other people. Even small things such as how they configured their editor or their terminal.&lt;/p&gt;
&lt;p&gt;Now, I get it - not everyone loves pair programming. If that’s the case, don’t worry! There are other approaches to follow that can still provide you with valuable feedback and help you learn from your peers. Interactive code reviews and show-and-tell sessions are great alternatives that allow you to share your work and receive feedback without having to work together in real time.&lt;/p&gt;
&lt;p&gt;In the end, the most important thing is to remain open to new ideas and approaches. By continuing to learn and grow, you’ll be well on your way to becoming a senior software developer. So why not give pair programming a try and see what you can learn?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A pair of dogs who are not pair programming, but let&amp;amp;#x27;s pretend they are&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1400&quot; height=&quot;934&quot; src=&quot;https://loige.co/_astro/not-pair-programming-dogs.DsZQ4J7w_1AIN9A.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Photo by &lt;a href=&quot;https://unsplash.com/@itfeelslikefilm?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Janko Ferlič&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/9Yzy1ZVS7xc?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;h3 id=&quot;content-creation&quot;&gt;Content creation&lt;/h3&gt;
&lt;p&gt;First off, creating content can take many forms: articles, talks, videos, Twitter threads, you name it! And guess what? You don’t need to be an expert to share something new you learned. Even if you’re just starting on a given subject, your fresh perspective can bring value to others and help you establish yourself as a thought leader. So do create content on what it felt like to try a new programming language or a framework. What did you like? Was there something confusing? What did you miss from your previous experience?&lt;/p&gt;
&lt;p&gt;But here’s the thing: you gotta make it a habit. Commit to a regular schedule, and you’ll develop discipline and consistency in your content creation. Plus, the more you create, the more you’ll hone your communication skills. And I’ll say it one more time, communication is a critical skill for any senior engineer.&lt;/p&gt;
&lt;p&gt;And speaking of communication, that’s where content creation shines. As engineers, we love getting lost in technical details, but explaining complex concepts to non-technical stakeholders can be a challenge. By creating content, you’ll learn to communicate your ideas in a way that’s accessible and engaging to a broader audience. Plus, you’ll have an opportunity to get feedback on your content and, if you listen to feedback, you can improve your communication skills even further.&lt;/p&gt;
&lt;p&gt;Have heard of the concept of &lt;a href=&quot;https://www.ship30for30.com/post/how-to-write-an-atomic-essay-a-beginners-guide&quot;&gt;“atomic essays”&lt;/a&gt;? That just means breaking down your ideas into shorter, more focused pieces of content. This approach can make your content more engaging and easier to consume - especially on platforms like Twitter, where brevity is key. If you don’t know what kind of content to create, this could be a good format to start with.&lt;/p&gt;
&lt;p&gt;If you don’t know what to create content about, here’s my tip: every day, at the end of your work day write down 1 new thing that you think learned during that day. At the end of the work week, review your 5 points. I am sure that at least one of these will be worth creating some content about.&lt;/p&gt;
&lt;p&gt;Creating content can help you become a more senior engineer by establishing yourself as a thought leader, developing your communication skills, and contributing to the community. So go ahead and share your knowledge with the world. You will be surprised at how much impact it will have on yourself and others!&lt;/p&gt;
&lt;h3 id=&quot;other-ideas&quot;&gt;Other ideas&lt;/h3&gt;
&lt;p&gt;Here are some other random-ish tips that you can add to the ones above.&lt;/p&gt;
&lt;p&gt;First off, always try to keep a positive attitude. When things get tough, it’s easy to get discouraged and lose sight of the bigger picture. But remember, with enough time and resources, teams can overcome any challenge. When that luxury is missing, I am sure there are decent compromises that can meet everyone’s needs.&lt;/p&gt;
&lt;p&gt;Another key to upskilling is to avoid being too picky about technology or programming styles. Make an effort to expose yourself to different ways of solving problems. It’s an exercise for your problem-solving skills.&lt;/p&gt;
&lt;p&gt;It’s important to support our colleagues’ ideas, even if we would have done things differently. This kind of collaborative attitude helps build trust and fosters a culture of innovation and teamwork. Also, next time you will propose something, I am sure that people will be willing to discuss and support your ideas.&lt;/p&gt;
&lt;p&gt;When it comes to taking on tough jobs, don’t be afraid to volunteer. What about that refactoring that nobody wants to do? Step up and take it on. Those messy, complicated parts of the code that everyone avoids? Dive in and try to make sense of them. By taking on these challenging tasks, you can develop a reputation as a problem solver and become the go-to person for the toughest jobs.&lt;/p&gt;
&lt;p&gt;Finally, as a general rule, try to make things just a little bit better wherever you have the chance. Whether it’s by documenting a process, improving an application’s user interface, or streamlining a workflow, every small improvement counts. Over time, these small wins can add up and help us become more valuable team members.&lt;/p&gt;
&lt;h2 id=&quot;how-do-i-sell-myself-as-a-senior&quot;&gt;How do I sell myself as a senior?&lt;/h2&gt;
&lt;p&gt;If I think I am a senior engineer what can I do to be recognised as one?&lt;/p&gt;
&lt;p&gt;First, start by taking on more responsibility. Look for opportunities to lead projects or mentor junior engineers. Share your knowledge and experience with others and provide guidance.&lt;/p&gt;
&lt;p&gt;Secondly, try to make an impact beyond your immediate team or project. Participate in cross-functional initiatives, contribute to open-source projects, or speak at industry events. These types of activities can help you establish yourself as a thought leader in your field and demonstrate your expertise to a wider audience.&lt;/p&gt;
&lt;p&gt;Thirdly, focus on developing your soft skills. As a senior engineer, you will be expected to communicate effectively with both technical and non-technical stakeholders, lead meetings, and negotiate effectively. So work on improving your communication, leadership, and conflict resolution skills to become a well-rounded and respected member of your team.&lt;/p&gt;
&lt;p&gt;Another way to demonstrate your expertise is by sharing your knowledge with others. Write technical blog posts, record tutorial videos, or speak at internal or external events to showcase your expertise and demonstrate your willingness to help others learn.&lt;/p&gt;
&lt;p&gt;Lastly, seek feedback from your colleagues, mentors, and managers. Ask for constructive criticism and be open to suggestions for improvement. By being receptive to feedback, you can continuously improve your skills and demonstrate your commitment to growing and learning as a senior engineer.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A software engineer in the sunlight raising their fist to the sky in sign of victory&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1910&quot; height=&quot;1091&quot; src=&quot;https://loige.co/_astro/a-software-engineer-who-definitely-wants-to-be-recognised-as-senior.DXckjEi9_U9ASL.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Photo by &lt;a href=&quot;https://unsplash.com/fr/@mbrunacr?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Miguel Bruna&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/TzVN0xQhWaQ?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The definition of a senior software engineer is complex and multifaceted, but it generally involves possessing a deep technical expertise, a broad understanding of the industry, and a range of soft skills that enable effective communication, leadership, and problem-solving.&lt;/p&gt;
&lt;p&gt;To become a senior software engineer, it’s important to continually develop and refine your skills, focusing not just on technical abilities but also on communication, leadership, and business acumen.&lt;/p&gt;
&lt;p&gt;This might involve pair programming, creating content, volunteering for challenging projects, and seeking out new learning opportunities.&lt;/p&gt;
&lt;p&gt;Ultimately, the path to seniority is not a linear one, and it requires dedication, perseverance, and a growth mindset to continue improving and evolving as a software engineer. So keep pushing yourself to go one level deeper, to have fun and find joy in your work, and to always strive to make a positive impact on your team and organization.&lt;/p&gt;
&lt;p&gt;But if you have been wondering all the time whether I have been describing the &lt;em&gt;perfect&lt;/em&gt; senior software engineer, let me only tell you that I am not expecting people to nail every single aspect mentioned in this article. There will be things you will be great at and others where you’ll be barely sufficient. That’s just human nature and it’s okay!&lt;/p&gt;
&lt;p&gt;We cannot excel at everything but we should know our strengths and weaknesses work with our team to amplify strengths and compensate for weaknesses …and strive to get better every day!&lt;/p&gt;
&lt;p&gt;It’s a journey, not a destination! Touché…&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/the-senior-dev.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/the-senior-dev.png" width="1200" height="630"/></media:content><category>life</category><category>career</category><author>Luciano Mammino</author><comments>https://loige.co/the-senior-dev/#comments</comments><enclosure url="https://loige.co/og/the-senior-dev.png" length="0" type="image/png"/></item><item><title>Why you should consider Rust for your Lambdas</title><link>https://loige.co/why-you-should-consider-rust-for-your-lambdas/</link><guid isPermaLink="true">https://loige.co/why-you-should-consider-rust-for-your-lambdas/</guid><description>Rust is an ideal language for writing AWS Lambda functions. Its performance can reduce execution time and memory usage, lowering costs. Its safety features like no nulls and error handling can reduce bugs.</description><pubDate>Wed, 16 Aug 2023 09:58:00 GMT</pubDate><content:encoded>&lt;p&gt;Rust is such a cool language, even though it might take a bit to get the hang of
it. But trust me, the payoff is huge. As someone who’s all into serverless stuff
and loves playing around with AWS, I’ve been digging into how to write AWS
Lambda functions in Rust and whether it’s worth the sweat.&lt;/p&gt;
&lt;p&gt;MEGA-Spoiler: Yep, you guessed it from the title - it’s totally worth it. And in
this article, you’re gonna find out why, so stick around!&lt;/p&gt;
&lt;p&gt;Okay, so there’s this pic in the article of Morpheus holding a Lambda in one
hand and Ferry, the Rust mascot, in the other. But guess what? You don’t have to
pick just one. It’s not a do-or-die choice. You can have both cakes and eat them
too!&lt;/p&gt;
&lt;h2 id=&quot;what-is-serverless-and-why-do-i-like-it&quot;&gt;What is serverless and why do I like it&lt;/h2&gt;
&lt;p&gt;Let’s start with a bit of a generic intro. If you are already familiar with
&lt;a href=&quot;/tag/serverless&quot;&gt;serverless&lt;/a&gt;, feel free to skip this section.&lt;/p&gt;
&lt;p&gt;How do we learn anything these days? We ask ChatGPT, of course! So let’s see
what it thinks about serverless.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;ChatGPT defining serverless&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;800&quot; height=&quot;651&quot; src=&quot;https://loige.co/_astro/what-the-hell-is-serverless-chatgpt.G9IlpRXW_XziaV.webp&quot; &gt;&lt;/p&gt;
&lt;details title=&quot;What the hell is serverless?&quot;&gt;
&lt;summary&gt;&lt;strong&gt;Dear ChatGPT, what the hell is serverless?&lt;/strong&gt;&lt;/summary&gt;
&lt;p&gt;&lt;em&gt;Serverless is a cloud computing model where the cloud provider manages the
infrastructure and automatically allocates computing resources to execute code
in response to events or requests.&lt;/em&gt;&lt;/p&gt;&lt;em&gt;
&lt;p&gt;In traditional server-based architecture, the server is a dedicated machine that
runs constantly and waits for requests. However, in serverless architecture,
there are no servers to manage or provision. Instead, the cloud provider takes
care of the underlying infrastructure, automatically scaling the necessary
computing resources up and down based on the amount of incoming traffic.&lt;/p&gt;
&lt;p&gt;With serverless computing, developers only pay for the actual usage of their
application, not for the infrastructure. This makes serverless a cost-effective
option for running and scaling applications. Serverless computing also reduces
operational complexity, as the cloud provider takes care of infrastructure
maintenance, security, and availability.&lt;/p&gt;
&lt;/em&gt;&lt;p&gt;&lt;em&gt;Examples of serverless services include AWS Lambda, Azure Functions, and Google
Cloud Functions, which allow developers to execute code without managing servers
or infrastructure.&lt;/em&gt;&lt;/p&gt;
&lt;/details&gt;
&lt;p&gt;Pretty good definition for generative AI, but let me give you my (shorter)
summary:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Serverless, is a way of running applications in the cloud.&lt;/li&gt;
&lt;li&gt;Of course, there are servers somewhere, we just don’t have to manage them.&lt;/li&gt;
&lt;li&gt;We pay (only) for what we use.&lt;/li&gt;
&lt;li&gt;We code in small units of compute (functions), which are triggered by events.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, why is all of this very cool?&lt;/p&gt;
&lt;p&gt;In my experience, serverless helps with &lt;strong&gt;focusing a lot more on business
logic&lt;/strong&gt; and less on other concerns such as infrastructure, scalability, etc. Of
course, there’s still a learning curve and there are tradeoffs. We are not going
to get into the details in this article, so, for now, take this at face value:
serverless gives us more time to focus on what matters for the business:
providing value to the customers.&lt;/p&gt;
&lt;p&gt;Serverless can also &lt;strong&gt;increase team agility&lt;/strong&gt;. By virtue of forcing us to think
in terms of small, event-driven functions, we are forced to think about keeping
the code-base modular. This can help the team in many ways. For instance, it can
be easier to distribute and parallelise the work. Also, if at some point we
realise we want to rewrite or re-engineer part of the software since the various
units are generally more decoupled, it should be easier to do that. You might
have seen this one coming, but if we want to rewrite an entire piece of
functionality in Rust, we can do that without having to rewrite the entire code
base. We can change things incrementally, one function at a time! I am actually
in the process of rewriting a serverless project in Rust and I am doing it
&lt;a href=&quot;https://twitch.tv/loige&quot;&gt;live on Twitch&lt;/a&gt;
(&lt;a href=&quot;https://www.youtube.com/playlist?list=PLbNOKnE-Oyr1tsUft4j0QZDyk5iFcVVy_&quot;&gt;recordings here&lt;/a&gt;),
just in case you are curious to see some examples…&lt;/p&gt;
&lt;p&gt;Serverless gives us some degree of &lt;strong&gt;automatic scalability&lt;/strong&gt;. Lambdas will be
spawned up and down depending on the number of events happening. If we have a
sudden surge of user activity, the system is generally able to provide the
necessary amount of computing power to handle that. This is not an absolute. In
reality, it is important to understand how cloud providers achieve this level of
auto-scalability. The way they do it is not always effective for all use cases,
but in practice, it’s something that can help a lot and that works well for the
most common cases.&lt;/p&gt;
&lt;p&gt;So yes, serverless is great, but it’s important to say that &lt;strong&gt;it is not a silver
bullet&lt;/strong&gt;. Certain scenarios are still better implemented with bare metal virtual
machines, where you have to do all the hard work of managing servers… Or with
long-running containers deployed on some container orchestration platform, where
you have less infrastructure to manage, but still significantly more than what
you get with serverless functions.&lt;/p&gt;
&lt;h2 id=&quot;aws-lambda&quot;&gt;AWS Lambda&lt;/h2&gt;
&lt;p&gt;Let’s add another bit of context here. Feel free to skip it if you are already
familiar with what AWS Lambda is.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/lambda/&quot;&gt;AWS Lambda&lt;/a&gt; is the FaaS (Function as a Service)
offering from AWS.&lt;/p&gt;
&lt;p&gt;Lambda allows us to write your business logic as functions that are
automatically triggered when certain events happen.&lt;/p&gt;
&lt;p&gt;Just to give you some examples, such events could be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An HTTP request is made against an API Gateway&lt;/li&gt;
&lt;li&gt;A new file was created in an S3 bucket&lt;/li&gt;
&lt;li&gt;A new job was published in a Job queue&lt;/li&gt;
&lt;li&gt;A scheduled event&lt;/li&gt;
&lt;li&gt;A manual invocation&lt;/li&gt;
&lt;li&gt;An invocation orchestrated by a workflow (e.g. a Step Function)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And to make things a bit more concrete, here are some realistic examples of what
we can do with this idea:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build an HTTP API that implements a payment gateway using API Gateway and
Lambda.&lt;/li&gt;
&lt;li&gt;Automatically generate thumbnails for new videos uploaded to an S3 bucket.&lt;/li&gt;
&lt;li&gt;Synchronise data from an FTP drive on a schedule&lt;/li&gt;
&lt;li&gt;Scrape data from a website&lt;/li&gt;
&lt;li&gt;Send welcome emails when a new user signs up (using an SQS queue or an Event
Bridge event)&lt;/li&gt;
&lt;li&gt;Analyse system and application logs and generate alarms for suspicious
activities&lt;/li&gt;
&lt;li&gt;Rotate secrets and restart the necessary applications&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And so much more…&lt;/p&gt;
&lt;p&gt;Lambda is pretty cool (you know I love it!), but it comes with some important
limitations.&lt;/p&gt;
&lt;p&gt;As of today, a Lambda execution &lt;strong&gt;cannot last more than 15 minutes&lt;/strong&gt;. Also,
&lt;strong&gt;the payload size is limited&lt;/strong&gt; (both request and response payloads are
constrained). And finally, &lt;strong&gt;you cannot have a lambda with a GPU&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;There are other subtleties, but these limitations alone should make you think
about some use cases where Lambda wouldn’t be a great fit. Therefore, don’t try
to do everything with Lambda. It’s not another silver bullet (in tech, nothing
is, really)!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Using AWS Lambda like a hammer for every nail&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;600&quot; height=&quot;338&quot; src=&quot;https://loige.co/_astro/lambda-for-everything.CMDUvDdt_Z15Sid4.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;If everything you have is a &lt;del&gt;Lambda&lt;/del&gt; hammer…😏&lt;/p&gt;
&lt;h2 id=&quot;aws-lambda-pricing-model&quot;&gt;AWS Lambda pricing model&lt;/h2&gt;
&lt;p&gt;One of the reasons why I think Rust is a promising solution for writing Lambda
functions is because of potential pricing implications, therefore it is
important to understand Lambda’s pricing model.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://aws.amazon.com/lambda/pricing/&quot;&gt;pricing model for AWS Lambda&lt;/a&gt; is
(relatively) simple and it’s based on the idea that &lt;em&gt;we should pay only for what
we use&lt;/em&gt;. The actual formula is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Cost = Allocated Memory ✖️ Execution Time&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To better understand what this means in practice, let’s discuss an example.&lt;/p&gt;
&lt;p&gt;Let’s say we create a new Lambda function and assign &lt;code&gt;512 MB&lt;/code&gt; of RAM to it. At
the time of writing in the &lt;code&gt;eu-west-1&lt;/code&gt; region (Ireland) the cost per millisecond
for this configuration is &lt;code&gt;$ 0.000_000_008_300&lt;/code&gt;. How many zeroes is that?!
Anyway, let’s say we run this function for the maximum time available: 15
minutes, ergo &lt;code&gt;900_000 ms&lt;/code&gt;, this is what we end up with:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;$ 0.000_000_008_300 * 900_000 ms = 0.&lt;em&gt;007&lt;/em&gt; $&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img alt=&quot;James Bond - 007, like .007 cents of a dollar. Yes, a very bad joke!&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;665&quot; height=&quot;375&quot; src=&quot;https://loige.co/_astro/james-bond-007.B7QmFqhK_Z1UK6ra.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Yes, &lt;em&gt;007&lt;/em&gt; … I know this was a bad joke, but let’s pretend you liked it and
let’s move on… 😅&lt;/p&gt;
&lt;p&gt;The real question is: is &lt;em&gt;.007 $&lt;/em&gt; a lot? Or is it very cheap? Well, I guess &lt;em&gt;it
depends&lt;/em&gt; (of course it does!).&lt;/p&gt;
&lt;p&gt;If we are running this Lambda function once a week, it’s basically for free…
If we are running it a thousand times per minute, we end up paying about &lt;em&gt;300.00
$&lt;/em&gt; per month, which isn’t my definition of cheap! And imagine what happens if we
have thousands of requests per second!&lt;/p&gt;
&lt;p&gt;But this should give you an idea of the pricing model and how it scales.&lt;/p&gt;
&lt;p&gt;In general, for unpredictable usage patterns (sporadic or very spiky
invocations), Lambda tends to be a cheap solution, but when you have a
consistently high rate of invocations, it might get quite expensive and there
could be significantly cheaper alternatives.&lt;/p&gt;
&lt;p&gt;When it comes to serverless, it’s also important to consider the &lt;strong&gt;TCO (Total
Cost of Ownership)&lt;/strong&gt; which should also include the cost of maintaining the
infrastructure (provisioning, patching, security, etc.). This tends to be very
low with serverless, while it gets more expensive with more traditional
approaches.&lt;/p&gt;
&lt;p&gt;So, yeah, cost is always a complex matter, but if you want to deep dive into
better understanding how the price equation might influence your choice of
computing technology, I’d recommend reading this excellent article:
&lt;a href=&quot;https://www.infoq.com/articles/aws-lambda-price-change/&quot;&gt;“Why AWS Lambda Pricing Has to Change for the Enterprise
”&lt;/a&gt; by
&lt;a href=&quot;https://twitter.com/eoins&quot;&gt;Eoin Shanaghy&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;lambda-functions-and-cpu-allocation&quot;&gt;Lambda functions and CPU allocation&lt;/h2&gt;
&lt;p&gt;Now, you might be wondering, how come CPU doesn’t come into play in the pricing
model? What if we need to run a very CPU-intensive task and we would like to
have multiple cores to distribute the load and speed up the computation?&lt;/p&gt;
&lt;p&gt;Well, the catch is that we don’t &lt;em&gt;explicitly&lt;/em&gt; get to configure the number of
vCPUs, we automatically get a certain amount of vCPUs proportionally to how much
memory we are configuring for our Lambda.&lt;/p&gt;
&lt;p&gt;The number of vCPUs that we will get can be seen in the following table:&lt;/p&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Memory&lt;/th&gt;&lt;th&gt;vCPUs&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;128 - 3008 MB&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3009 - 5307 MB&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5308 - 7076 MB&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;7077 - 8845 MB&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;8846+ MB&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Note that this is not an &lt;em&gt;official table&lt;/em&gt; but the result of an independent
&lt;a href=&quot;https://stackoverflow.com/a/66523153/495177&quot;&gt;study by SentiaTech&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The takeaway here is that, if we need more CPU, we are forced to provision more
memory, even if we don’t need all of that memory… and yes, increasing the
memory will increase the price per millisecond of execution. But that doesn’t
necessarily mean that the executions will be more expensive because with more
CPU we might be able to finish the task much faster, therefore we are billed for
a smaller amount of milliseconds. I know, it’s tricky to find the sweet spot
between memory, CPU and price. If you are looking for a tool to help you out,
check out the excellent
&lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/operatorguide/profile-functions.html&quot;&gt;Lambda Power Tuning&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Anyway, even though it sucks not to be able to specify exactly how much CPU we
need, this model keeps things simple for most use cases… Having to think about
only 2 dimensions (time and memory) keeps pricing and configuration rather
straightforward.&lt;/p&gt;
&lt;p&gt;… and most likely it also helps the Lambda team to allocate our Lambdas
efficiently in their compute clusters.&lt;/p&gt;
&lt;h2 id=&quot;the-execution-model-of-a-lambda-function&quot;&gt;The execution model of a Lambda function&lt;/h2&gt;
&lt;p&gt;We have seen that the whole promise of Lambda, being a &lt;em&gt;serverless&lt;/em&gt; service, is
that we only pay for what we use.&lt;/p&gt;
&lt;p&gt;For this pricing model to work, the Lambda team has to be very savvy with the
allocated resources, ideally provisioning them only when they are needed and
de-provisioning them as soon as they are not needed anymore.&lt;/p&gt;
&lt;p&gt;How does this happen? Without getting too technical, this is a high-level
overview:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When we deploy a Lambda function, we are shipping its code into an S3 bucket.
So, in a way, we are &lt;em&gt;just saving files in the cloud&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Lambda functions are event-based. So this means that when an &lt;em&gt;event trigger&lt;/em&gt;
happens, AWS should be able to execute the code we provisioned.&lt;/li&gt;
&lt;li&gt;To execute the code, AWS needs to allocate some computing resources. In the
case of Lambda, this means spawning a
&lt;a href=&quot;https://firecracker-microvm.github.io/&quot;&gt;Firecracker&lt;/a&gt; micro-VM somewhere and
initializing it with the code from our S3 bucket.&lt;/li&gt;
&lt;li&gt;This operation might take some time. After all, we need to think that behind
the scenes, AWS is downloading the code from S3 and spinning up a VM. They
surely have very efficient ways of doing that, but it can still result in
noticeable delays in the order of hundreds of milliseconds. When this happens
it is called a &lt;strong&gt;cold start&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Once the VM is up and running, the Lambda execution environment can &lt;em&gt;invoke&lt;/em&gt;
our lambda and pass the event data.&lt;/li&gt;
&lt;li&gt;Once the execution is completed, the runtime doesn’t immediately destroy the
instance. If the same type of event happens in a short amount of time, the
instance is &lt;em&gt;re-used&lt;/em&gt;, which means that the new event will be passed into it.
This saves us from having to endure another cold start. This might happen
multiple times, especially if we have events being generated at a consistent
rate.&lt;/li&gt;
&lt;li&gt;But let’s assume that at some point we stop receiving events for a few
minutes. At this point, the Lambda runtime might decide to reclaim the
resources allocated for our Lambda instance and then it shuts it down and
de-provisions it.&lt;/li&gt;
&lt;li&gt;If a new event will come in at some point in the future, the whole lifecycle
will start again.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;A diagram illustrating the main phases of the execution model of an AWS Lambda Function, taken from the AWS documentation&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1600&quot; height=&quot;300&quot; src=&quot;https://loige.co/_astro/lambda-execution-lifecycle.DAVmRTbi_PKkNl.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;If you want to go more in detail, I recommend reading about the
&lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtime-environment.html&quot;&gt;Lambda execution environment&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;why-rust--lambda--️&quot;&gt;Why Rust + Lambda = ❤️?&lt;/h2&gt;
&lt;p&gt;Ok, we are finally here! Now that we have covered enough background knowledge,
we should be able to make the point that Rust is an ideal language to write
Lambda functions with.&lt;/p&gt;
&lt;h3 id=&quot;cost-saving&quot;&gt;Cost saving&lt;/h3&gt;
&lt;p&gt;The first reason why Rust is so cool for Lambda functions is that Rust is a
typed and compiled language which produces very efficient binaries. If well
written, Rust code can be on par in terms of speed with equivalent C or C++
code. Other than being very performant, these binaries are generally very memory
efficient and very small in size.&lt;/p&gt;
&lt;p&gt;All these characteristics are perfectly aligned with all the billing dimensions
we have with Lambda, so &lt;strong&gt;Lambda function written in Rust can be much cheaper
than most alternative languages&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;To summarise this point:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The performance will likely reduce the number of ms needed to complete the
execution.&lt;/li&gt;
&lt;li&gt;The memory efficiency might allow us to keep the allocated memory low.&lt;/li&gt;
&lt;li&gt;The small binary size might reduce the duration of cold starts (less time
needed to fetch the code from S3).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Regarding cold starts, there is
&lt;a href=&quot;https://maxday.github.io/lambda-perf/&quot;&gt;a fantastic benchmark by Maxime David&lt;/a&gt;,
and guess what? Rust is the fastest runtime in terms of cold start! And by far!&lt;/p&gt;
&lt;p&gt;If you have a very hot Lambda that you are running thousands of times per day
and you used Java, Python or Node.js, and you are looking for opportunities to
reduce your AWS billing, consider rewriting this one Lambda in Rust.&lt;/p&gt;
&lt;p&gt;After all, that’s the beauty of Lambda-based architectures: Lambda functions are
generally very small and decoupled, so it should be possible to rewrite one of
them without having to touch the rest of your infrastructure.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Writing Lambda functions in Rust can save you some sweet money&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;480&quot; height=&quot;480&quot; src=&quot;https://loige.co/_astro/rust-saves-you-sweet-money.BJw7_q8K_Z1Vryh9.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Thank you, dear Rust, for helping us to save some sweet money. Cheers to you!&lt;/p&gt;
&lt;p&gt;Now, I know what you are thinking…&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“But having to learn Rust, will cost me sweet money and time too!”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;Tru dat!&lt;/em&gt; 🤷‍♂️&lt;/p&gt;
&lt;p&gt;Of course, you need to evaluate whether the juice is worth the squeeze case by
case, but what I would say in response to that is &lt;em&gt;“Well, yes. But consider it
as an investment!”&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;memory-safety&quot;&gt;Memory safety&lt;/h3&gt;
&lt;p&gt;This is one of the main propositions of Rust. Rust was created with the intent
of eliminating an entire class of memory and threading bugs. These kinds of bugs
have been one of the main sources of security issues for a few decades! Even
Microsoft believes that
&lt;a href=&quot;https://msrc.microsoft.com/blog/2019/07/a-proactive-approach-to-more-secure-code/&quot;&gt;if they had written Windows in a language with the guarantees of Rust they would have avoided 70% of their security issues&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;But, in practice, what does this mean for Lambda?&lt;/p&gt;
&lt;p&gt;The way I see it is that most developers (or maybe it’s just me) are scared
about writing multi-threaded code and therefore we end up trying to avoid doing
that. Which means we might be losing precious opportunities to optimize our
algorithms.&lt;/p&gt;
&lt;p&gt;In the context of Lambda, this means potentially longer execution times, which
again might be another reason for an unnecessarily large bill.&lt;/p&gt;
&lt;p&gt;Since Rust can give you the confidence that your multi-threaded code is safe (if
it compiles it is safe), this might encourage scared developers like me to try
to leverage more opportunities to write multi-threaded code.&lt;/p&gt;
&lt;p&gt;Isn’t that a nice proposition?&lt;/p&gt;
&lt;h3 id=&quot;fewer-bugs&quot;&gt;Fewer bugs&lt;/h3&gt;
&lt;p&gt;Ok, this is probably the most opinionated point I have about Rust. But having
written enough Rust in the last 4 years, I came to the realisation that when I
write code in Rust, it generally just works. Or to put it more sincerely, it’s
generally less buggy than it would be compared to using other languages such as
JavaScript, Python, or Java.&lt;/p&gt;
&lt;p&gt;This is not because Rust is magic or because you become some kind of super
programmer with it. I honestly think that it’s just due to some clever language
design decisions that force you to think more about the cases when things can go
wrong.&lt;/p&gt;
&lt;p&gt;In particular, I am referring to the fact the the language has no &lt;code&gt;null&lt;/code&gt; types.
If something may or may not exist, the language forces you to handle that
explicitly using the
&lt;a href=&quot;https://doc.rust-lang.org/std/option/enum.Option.html&quot;&gt;&lt;code&gt;Option&lt;/code&gt; type&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also, the language doesn’t have a concept of exceptions. You can’t just throw
stuff wherever you want. When something can fail, you also need to explicitly
use the &lt;a href=&quot;https://doc.rust-lang.org/std/result/&quot;&gt;&lt;code&gt;Result&lt;/code&gt; type&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I have been loving using these constructs and, in retrospect, I wish that
languages like Python and JavaScript had something like that. They just make it
so much more obvious when something can go wrong in your business logic and
force you to think about a way to handle these edge cases.&lt;/p&gt;
&lt;p&gt;Now, just to be clear, I am not promising Rust will magically solve all your
bugs 🐞. You’ll still write buggy code (that’s probably inevitable), but I am
sure your code will be much more well thought out and that you’ll be
automatically handling many more error cases compared to using other languages
where you can just assign stuff to &lt;code&gt;null&lt;/code&gt; or throw random exceptions here and
there without thinking too much about the possible consequences of these
decisions…&lt;/p&gt;
&lt;h2 id=&quot;where-do-we-start&quot;&gt;Where do we start?&lt;/h2&gt;
&lt;p&gt;Ok, did I convince you to entertain the idea of writing Lambda functions in
Rust?&lt;/p&gt;
&lt;p&gt;Yes? Great!&lt;/p&gt;
&lt;p&gt;So, now you are wondering where to start…&lt;/p&gt;
&lt;p&gt;This is probably a topic for a series of more hands-on articles, so stay tuned
for more.&lt;/p&gt;
&lt;p&gt;But if you really can’t wait, I will be hosting a talk titled
&lt;a href=&quot;https://www.meetup.com/rust-dublin/events/294587280/&quot;&gt;“Rust, Serverless and AWS
” at the next Rust Dublin Meetup&lt;/a&gt;
on Tuesday, August 22nd, 2023.&lt;/p&gt;
&lt;p&gt;In this talk, I will show many practical code examples and use cases and some of
the tooling you can use today to bootstrap, test and deploy Lambda functions
written in Rust.&lt;/p&gt;
&lt;p&gt;If you are not in Dublin, you can join the event anyway. There will be a live
stream as well 🙂&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: here’s the recording of the talk, I hope you’ll enjoy it&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em; margin-top: 2em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://www.youtube.com/embed/He4inXmMZZI&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Finally, if you think your organisation needs help with Serverless or with
reducing your AWS bills, consider
&lt;a href=&quot;https://fourtheorem.com/contact-us/?utm_source=loige_co&amp;#x26;utm_medium=article&amp;#x26;utm_campaign=loige_co_rust_lambda_article&amp;#x26;utm_id=loige_co_rust_lambda_article&amp;#x26;utm_term=rust+lambda+serverless&amp;#x26;utm_content=writing+lambdas+in+rust&quot;&gt;reaching out to fourTheorem&lt;/a&gt;.
We are a consulting company specialised in serverless and all things AWS, and I
like to think we are lovely to work with. 😊&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Rust is a really cool programming language and it’s something we should consider
using for writing Lambda functions.&lt;/p&gt;
&lt;p&gt;Due to its characteristics and design choices, Rust might help us to save money
on our lambda function and to write more correct (read “less buggy”) Lambda
code.&lt;/p&gt;
&lt;p&gt;So, here’s a choice. &lt;strong&gt;Do you pick Lambda or do you pick Rust? Why don’t you
pick both?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;👋&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/why-you-should-consider-rust-for-your-lambdas.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/why-you-should-consider-rust-for-your-lambdas.png" width="1200" height="630"/></media:content><category>rust</category><category>serverless</category><author>Luciano Mammino</author><comments>https://loige.co/why-you-should-consider-rust-for-your-lambdas/#comments</comments><enclosure url="https://loige.co/og/why-you-should-consider-rust-for-your-lambdas.png" length="0" type="image/png"/></item><item><title>JavaScript, low-level or AI?</title><link>https://loige.co/javascript-low-level-or-ai/</link><guid isPermaLink="true">https://loige.co/javascript-low-level-or-ai/</guid><description>The software industry sees an interesting tension between generative AI capturing the software lifecycle and low-level languages aiming for better performance. As developers we must understand these trends and find a strategy. Learn one or both?</description><pubDate>Fri, 10 Nov 2023 14:37:00 GMT</pubDate><content:encoded>&lt;p&gt;The software industry is going to be fun to see in the coming 5-10 years.&lt;/p&gt;
&lt;p&gt;I see an interesting tension happening right now…&lt;/p&gt;
&lt;h2 id=&quot;the-generative-ai-side&quot;&gt;The generative AI side&lt;/h2&gt;
&lt;p&gt;On one side we have &lt;strong&gt;generative AI&lt;/strong&gt; capturing almost every bit of the software development lifecycle and effectively becoming a new high-level abstraction, possibly the highest level we have ever seen in our industry.&lt;/p&gt;
&lt;p&gt;There seems to be no stopping this phenomenon… just looking at the latest announcements from GitHub Universe, it’s clear that we will have to adopt AI in one way or another and this is not necessarily a bad thing if it truly makes us all more productive and focused on generating business value.&lt;/p&gt;
&lt;p&gt;If you don’t know what I am talking about you should check out this video:&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://www.youtube.com/embed/KqIGLh1EBOw&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;And if that’s not enough you should watch the &lt;a href=&quot;https://www.youtube.com/live/h3Bwuzz0TNA?si=db6QZULbBgdhFSe9&quot;&gt;full GitHub Universe 2023 keynote&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/live/h3Bwuzz0TNA?si=db6QZULbBgdhFSe9&amp;#x26;t=5414&quot;&gt;&lt;img alt=&quot;GitHub Universe 2023, Day 1, Thomas Dohmke on stage with a slide in the background saying &amp;quot;One more thing&amp;quot;, mimicking the Steve Job&amp;amp;#x27;s launch of the iPad&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;790&quot; height=&quot;460&quot; src=&quot;https://loige.co/_astro/github-universe-2023-day1-one-more-thing.CkxCYsbi_ZT4GNi.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;&lt;em&gt;GitHub Universe 2023, Day 1. Thomas Dohmke on stage with a slide in the background saying “One more thing”, mimicking the Steve Job’s launch of the iPad&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;The part that impressed me the most is that now Copilot can also help you lay out the structure of a project, breaking down requirements into potential tasks. Once you are happy with the result, it can start to work on the individual tasks and submit PRs. This is called &lt;a href=&quot;https://githubnext.com/projects/copilot-workspace&quot;&gt;Copilot workspace&lt;/a&gt;, if you want to have a look.&lt;/p&gt;
&lt;p&gt;It seems too good to be true and it’s probably going to be far from perfect for a while, but there’s great potential for efficiency here, and I am sure GitHub (and other competitors) will keep investing in this kind of products and maybe in a few years, we’ll be mostly reviewing and merge AI-generated PRs for the most common use cases.&lt;/p&gt;
&lt;p&gt;If you think that ChatGPT was launched slightly less than 1 year ago, what will we be seeing in 5 or 10 years from now?&lt;/p&gt;
&lt;h2 id=&quot;the-low-level-side&quot;&gt;The low-level side&lt;/h2&gt;
&lt;p&gt;On the other side, we have a wave of new low-level languages such as &lt;a href=&quot;/tag/go&quot;&gt;&lt;strong&gt;Go&lt;/strong&gt;&lt;/a&gt;, &lt;a href=&quot;/tag/rust&quot;&gt;&lt;strong&gt;Rust&lt;/strong&gt;&lt;/a&gt;, &lt;strong&gt;Zig&lt;/strong&gt; (and &lt;strong&gt;Carbon&lt;/strong&gt;, and &lt;strong&gt;Nim&lt;/strong&gt;, and &lt;strong&gt;Odin&lt;/strong&gt;, and &lt;strong&gt;VLang&lt;/strong&gt;, and &lt;strong&gt;Pony&lt;/strong&gt;, and &lt;strong&gt;Hare&lt;/strong&gt;, and &lt;strong&gt;Crystal&lt;/strong&gt;, and &lt;strong&gt;Julia&lt;/strong&gt;, and &lt;strong&gt;Mojo&lt;/strong&gt;, and.. I could keep going here… 🤷‍♀️).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The lovely Hare language mascot&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;256&quot; height=&quot;256&quot; src=&quot;https://loige.co/_astro/hare-language-mascot.DpVjoMf5_Z17q8N6.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;&lt;em&gt;OK, I really wanted to put the lovely Hare language mascot here. &lt;a href=&quot;https://harelang.org/&quot;&gt;Hare&lt;/a&gt; is a systems programming language designed to be simple, stable, and robust. Hare uses a static type system, manual memory management, and a minimal runtime. It is well-suited to writing operating systems, system tools, compilers, networking software, and other low-level, high-performance tasks.&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;All these languages take slightly different trade-offs, but, at the end of the day, they are built on the premise that we need to go lower level and have more fine-grained control over how we use memory, CPU, GPU and all the other resources available on the hardware. This is perceived as an important step to achieve better performance, lower production costs, and reach the dream of &lt;em&gt;“greener”&lt;/em&gt; computing.&lt;/p&gt;
&lt;p&gt;If you are curious to know why we should be caring about &lt;em&gt;green computing&lt;/em&gt;, let’s just have a quick look at this report: &lt;a href=&quot;https://www.cso.ie/en/releasesandpublications/ep/p-dcmec/datacentresmeteredelectricityconsumption2022/keyfindings/&quot;&gt;Data Centres Metered Electricity Consumption 2022 (Republic of Ireland)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The report findings state that in 2022, in Ireland alone, data centers’ energy consumption increased by 31%. This increase amounts to an additional 4,016 Gigawatt/hours. To put that in perspective we are talking about the equivalent of &lt;a href=&quot;https://www.energy.gov/eere/articles/how-much-power-1-gigawatt&quot;&gt;an additional 401.600.000.000 (402 billion!) LED light bulbs being lit every single hour&lt;/a&gt;. If you divide that by the &lt;a href=&quot;https://en.wikipedia.org/wiki/Demographics_of_the_Republic_of_Ireland&quot;&gt;population of the Republic of Ireland&lt;/a&gt; this is like every individual is powering ~80.000 additional LED light bulbs in their home, all day and night! And this is just the increase from 2021 to 2022… How friggin’ crazy is that?! 🤯&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Light! More light! - a picture by D A V I D S O N L U N A with tons of light bulbs hanging from the ceiling&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;640&quot; height=&quot;427&quot; src=&quot;https://loige.co/_astro/d-a-v-i-d-s-o-n-l-u-n-a-VoaI7RNKzp4-unsplash.D0A93Bm8_Z24VsM2.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small style=&quot;text-align: center&quot;&gt;Photo by &lt;a href=&quot;https://unsplash.com/@davidsonluna?utm_content=creditCopyText&amp;#x26;utm_medium=referral&amp;#x26;utm_source=unsplash&quot;&gt;D A V I D S O N L U N A&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/clear-glass-pendant-lamps-turned-on-during-night-time-VoaI7RNKzp4?utm_content=creditCopyText&amp;#x26;utm_medium=referral&amp;#x26;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;Ok, now one could argue that we had low-level languages pretty much since the software industry was invented. So why isn’t that the default and why do we bother wasting energy with higher-level programming languages?&lt;/p&gt;
&lt;p&gt;That’s actually quite simple: because coding in low-level programming languages such as &lt;strong&gt;C&lt;/strong&gt; and &lt;strong&gt;C++&lt;/strong&gt; is hard! Like really really hard! And it’s also time-consuming and therefore expensive for companies! And I am not even going to mention the risk of security issues that come with these languages.&lt;/p&gt;
&lt;p&gt;So why should this new wave of low-level programming language change things?&lt;/p&gt;
&lt;p&gt;Well, my answer is that they are trying to make low-level programming more accessible and safe. They are trying to create paradigms that could be friendly enough to be used for general computing problems (not just low-level), which could potentially bring the benefits of performance and efficiency even in areas where historically we have been using higher-level languages and made the hard tradeoff of fast development times vs sub-optimal performance.&lt;/p&gt;
&lt;p&gt;Take for example Rust. It was historically born to solve some of the hard problems that Mozilla had to face while building Firefox. But now it’s being used in many other areas, including embedded systems, game development, and even web development. Not just on the backend, but even on the frontend using WebAssembly!&lt;/p&gt;
&lt;p&gt;I am not going to claim that writing stuff in Rust is easier than doing the same in &lt;a href=&quot;/tag/javascript&quot;&gt;JavaScript&lt;/a&gt; or &lt;a href=&quot;/tag/python&quot;&gt;Python&lt;/a&gt;, but it’s definitely easier than doing the same in C or C++.&lt;/p&gt;
&lt;p&gt;So there might be many cases where we will be able to use these new languages to achieve better performance and efficiency without having to pay a massive development price for using a low-level language.&lt;/p&gt;
&lt;p&gt;And I would go as far as saying that these use cases exist in the industry today and there’s a staggering lack of talent in these areas.&lt;/p&gt;
&lt;h2 id=&quot;why-the-tension&quot;&gt;Why the tension?&lt;/h2&gt;
&lt;p&gt;So, is there really a tension here between generative AI-driven development and using low-level languages or are these just two very disjoint things?&lt;/p&gt;
&lt;p&gt;I would personally say yes, there’s a tension.&lt;/p&gt;
&lt;p&gt;Again, generative AI is pushing us to care less about the details. We trade our time and attention for the ability to focus on the business value and let the AI do the rest. This is a trend that has been going on for a while now and it’s not going to stop anytime soon.&lt;/p&gt;
&lt;p&gt;Investing in using a low-level language goes in the opposite direction. It’s a bet that we can achieve better performance and efficiency by going lower level and deciding to be explicit about the minutia of how we want to use the hardware at best.&lt;/p&gt;
&lt;p&gt;But, wait… Am I saying that AI is not going to be able to write efficient and hyper-optimised low-level code? 🤔&lt;/p&gt;
&lt;p&gt;Maybe! Or, at least my belief is that, as with any abstraction, there’s always a price to pay. And the price of using AI is that we are going to be less explicit about the details and therefore we are going to be less efficient.&lt;/p&gt;
&lt;p&gt;But I also expect this equation to change with time. As AI improves, it might be able to generate more efficient code. Possibly even better than code we would write manually, even with tons of expertise on our side.&lt;/p&gt;
&lt;h2 id=&quot;what-can-we-do-as-software-developers&quot;&gt;What can we do as software developers&lt;/h2&gt;
&lt;p&gt;Where does that leave us?&lt;/p&gt;
&lt;p&gt;As individual software engineers, we can’t expect to be able to change these trends. We can only try to understand them and adapt.&lt;/p&gt;
&lt;p&gt;Investing in learning a new language is a multi-year effort, and although it might be fun (if you are a language nerd like me), it is time that you might be taking away from other activities that might be more rewarding in the long term or just more valuable to you. For instance, you could be learning more about generative AI, right? 🤓&lt;/p&gt;
&lt;p&gt;My personal bet is to invest in both! I am currently learning Rust and I am also trying to keep up with the latest developments in the AI space.&lt;/p&gt;
&lt;p&gt;For instance, &lt;a href=&quot;https://twitter.com/eoins&quot;&gt;Eoin&lt;/a&gt; and I just released &lt;a href=&quot;https://awsbites.com/103-building-genai-features-with-bedrock/&quot;&gt;a new episode of AWS Bites where we explore Bedrock&lt;/a&gt;, AWS generative AI service… Check it out if you are curious to find out what we built with it!&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://www.youtube.com/embed/u945tsm4p7M&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;I am not sure how much I will be able to keep up with both, but I am going to try my best.&lt;/p&gt;
&lt;p&gt;I tend to be a generalist and it’s only natural for me to try to explore a wide space of possibilities rather than going super deep on one specific topic.&lt;/p&gt;
&lt;p&gt;But I am also aware that this is not the best strategy for everyone. So, if you are a specialist, you might want to focus on one of these two areas and try to become an expert in that. It might come with a risk, but it might also come with a great reward.&lt;/p&gt;
&lt;p&gt;I am also of the belief that the more we learn the more we are capable of learning. So regardless if you decide to go wide or if you put all your eggs in one basket, the important thing is to always keep learning and keep an open mind.&lt;/p&gt;
&lt;p&gt;If the future takes an unprecedented turn and we all end up writing code in a new language that is generated by AI, I am sure that the skills we have acquired in the past will still be valuable and will help us to adapt to the new paradigm.&lt;/p&gt;
&lt;p&gt;Only the future will tell… And maybe, even after all this fuss, we’ll still be writing tons of JavaScript in 10 years from now! 😜&lt;/p&gt;
&lt;h2 id=&quot;what-do-you-think&quot;&gt;What do you think?&lt;/h2&gt;
&lt;p&gt;So what’s your opinion and what’s your strategy for the future? I’d love for you to strongly disagree with me… or not?! Either way, let me know what you think here in the comments or on &lt;a href=&quot;https://twitter.com/loige&quot;&gt;X, formerly Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;See you around and happy coding! 🤓&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/javascript-low-level-or-ai.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/javascript-low-level-or-ai.png" width="1200" height="630"/></media:content><category>opinion</category><category>javascript</category><category>rust</category><category>go</category><category>ai</category><author>Luciano Mammino</author><comments>https://loige.co/javascript-low-level-or-ai/#comments</comments><enclosure url="https://loige.co/og/javascript-low-level-or-ai.png" length="0" type="image/png"/></item><item><title>2022 - A year in Review</title><link>https://loige.co/2022-a-year-in-review/</link><guid isPermaLink="true">https://loige.co/2022-a-year-in-review/</guid><description>In 2022 Luciano Mammino was awarded AWS Serverless Hero, confirmed as Microsoft MVP, became Codemotion Ambassador, spoke at 25 events, produced 45 AWS Bites podcast episodes, streamed live coding 36 times, surpassed 8M downloads for Middy and much more. His plans for 2023 include growing his AWS and Serverless expertise, learning Rust and Solid.js.</description><pubDate>Tue, 20 Dec 2022 08:50:00 GMT</pubDate><content:encoded>&lt;p&gt;Yup, 2022 flew and it’s that time of the year again. I want to write that boring post that I am the only one to look forward to writing and I don’t expect anyone to read.&lt;/p&gt;
&lt;p&gt;Well, if you are brave enough to go ahead and read it, let me say thank you and then, to follow the tradition, let me greet you with a &lt;em&gt;boring&lt;/em&gt; GIF:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A yawning monkey&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;240&quot; height=&quot;167&quot; src=&quot;https://loige.co/_astro/booooring.Dp8i-lXt_ZponIh.webp&quot; &gt;&lt;/p&gt;
&lt;h2 id=&quot;becoming-an-aws-serverless-hero&quot;&gt;Becoming an AWS Serverless Hero&lt;/h2&gt;
&lt;p&gt;Let’s start by addressing the elephant in the room, the biggest (and most unexpected) achievement of the year: &lt;strong&gt;being awarded the title of &lt;a href=&quot;https://aws.amazon.com/developer/community/heroes/luciano-mammino/&quot;&gt;AWS Serverless Hero&lt;/a&gt; by AWS&lt;/strong&gt;! 🦸‍♂️&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Some of the latest AWS Heroes awarded in 2022, including Luciano Mammino the author of this post&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;884&quot; height=&quot;727&quot; src=&quot;https://loige.co/_astro/serverless-heroes.iPo7P0eG_2ntjvL.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Now, why is it a big deal to me? Let me quote AWS:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The AWS Heroes program recognizes a vibrant, worldwide group of AWS experts whose enthusiasm for knowledge-sharing has a real impact within the community. Heroes go above and beyond to share knowledge in a variety of ways including online via social media, blog posts, open source projects, videos, and forums; or in person at conferences, workshops, and user group events.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I have surely done a good amount of work in this sense and I am really happy to get the recognition, but this one is very hard to get and I did not expect it at all.&lt;/p&gt;
&lt;p&gt;In addition to that, it’s not a program you can simply &lt;em&gt;apply&lt;/em&gt; to. AWS has obscure ways to discover and select potential heroes every year, and &lt;a href=&quot;https://aws.amazon.com/developer/community/heroes&quot;&gt;there aren’t that many worldwide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Heroes are divided into areas of expertise (Community, Container, Data, DevTools, Machine Learning, Serverless). I was awarded the Serverless hero title, which makes a lot of sense, since most of my AWS efforts have been around serverless in the last ~5 years.&lt;/p&gt;
&lt;p&gt;What I believe has been the most important thing that I have done in the realm of serverless is &lt;a href=&quot;https://middy.js.org&quot;&gt;middy&lt;/a&gt;, a Node.js middleware engine for AWS Lambda which allows you to organize your Lambda code, remove code duplication and focus more on business logic.&lt;/p&gt;
&lt;p&gt;And this brings me to the part where I have to say thank you to other people because without them I probably wouldn’t have gotten this recognition:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/willfarrell&quot;&gt;Will Farrell&lt;/a&gt;, maintainer of Middy. Will has done incredible work in the last 3 years taking Middy above and beyond. I wouldn’t have been able to keep the project going without Will’s hard work, so I am incredibly grateful for continuing from where I mostly left off. Thanks, Will!&lt;/li&gt;
&lt;li&gt;The amazing team at &lt;a href=&quot;https://fourtheorem.com&quot;&gt;fourTheorem&lt;/a&gt;, because I feel like I am learning and growing a lot by working with such a talented and enthusiastic team of professionals.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/eoins&quot;&gt;Eoin Shanaghy&lt;/a&gt; for sharing his endless knowledge with me and for being such a fantastic co-host for &lt;a href=&quot;https://awsbites.com/&quot;&gt;AWS Bites Podcast&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Tons of folks who have been inspirational in my AWS serverless journey: &lt;a href=&quot;https://twitter.com/theburningmonk&quot;&gt;Yan Cui&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/heitor_lessa&quot;&gt;Heitor Lessa&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/Sarutule&quot;&gt;Sara Gerion&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/mmeckes&quot;&gt;Matt Meckes&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/dreamorosi&quot;&gt;Andrea Amorosi&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/alexbdebrie&quot;&gt;Alex DeBrie&lt;/a&gt;, and many more that I am sure I am forgetting (sorry).&lt;/li&gt;
&lt;li&gt;All the other other heroes, for being such an incredible source of inspiration.&lt;/li&gt;
&lt;li&gt;All the AWS folks who decided to pick my name for the award!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What happens next? Well, for starting I got some cool swag. Thanks, AWS much appreciated.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;SWAG you receive after you become an AWS Hero&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;3489&quot; height=&quot;2321&quot; src=&quot;https://loige.co/_astro/aws_hero_swag.TIr1DWrN_2foczD.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Yeah, my box probably got a few kicks on the way…&lt;/p&gt;
&lt;p&gt;Other than that, you’ll probably see me posting more AWS and serverless-related content and most likely I will attend the re:Invent in 2023!&lt;/p&gt;
&lt;p&gt;Also, I want to take this opportunity to give a big thank you to the AWS Heroes team: &lt;a href=&quot;https://twitter.com/FarrahC32&quot;&gt;Farrah&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/taylorjacobsen&quot;&gt;Taylor&lt;/a&gt;, and Albert.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“With great power comes great responsibility”&lt;/p&gt;
&lt;p&gt;— Uncle Ben&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;confirmed-as-mvp&quot;&gt;Confirmed as MVP&lt;/h2&gt;
&lt;p&gt;In July I got a nice &lt;em&gt;azure&lt;/em&gt; postcard from Microsoft telling me that I got re-confirmed as MVP (Most Valuable Professional) for Developer Technologies for the years 2022 and 2023!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Luciano Mammino receives a postcard from Microsoft confirming he is an MVP for developer technologies&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;720&quot; height=&quot;480&quot; src=&quot;https://loige.co/_astro/luciano-mammino-reconfirmed-as-mvp-for-2022-2023-postcard.ClUFfJ8i_dtEFx.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://mvp.microsoft.com/&quot;&gt;Microsoft MVP program&lt;/a&gt; is somewhat similar to the AWS Hero program, meaning that it aims to reward people who contribute heavily to the tech industry by sharing their knowledge, creating content and practicing public speaking. The main difference from the Hero program is that the MVP program is much more generic, it does not necessarily focus on Microsoft technologies.&lt;/p&gt;
&lt;p&gt;It makes me incredibly proud to be recognized as such by Microsoft, especially considering that I am not a big user (nor promoter) of Microsoft products and languages.&lt;/p&gt;
&lt;p&gt;One cool thing about the MVP program is that they give you a little totem the first year and every year you get a new token that can be added to the stack!&lt;/p&gt;
&lt;p&gt;I should put it on a shelf at some point!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The Microsoft MVP totem&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1260&quot; height=&quot;962&quot; src=&quot;https://loige.co/_astro/luciano-mammino-reconfirmed-as-mvp-for-2022-2023.DCuRcfSl_ZrgdFT.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;You can also check out my &lt;a href=&quot;https://mvp.microsoft.com/en-us/PublicProfile/5004232&quot;&gt;MVP profile&lt;/a&gt; to make sure I am not lying to you. 😜&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Sharing is good, and with digital technology, sharing is easy”&lt;/p&gt;
&lt;p&gt;— Richard Stallman&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;codemotion-ambassador&quot;&gt;Codemotion Ambassador&lt;/h2&gt;
&lt;p&gt;In 2022 I got nominated Codemotion Ambassador!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The Codemotion ambassador program logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;684&quot; height=&quot;346&quot; src=&quot;https://loige.co/_astro/codemotion-ambassador-program.QZf3jCuD_27MKCo.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Codemotion is the biggest tech community in Italy and one of the biggest in Europe. They also organize some of the best tech conferences that I had the pleasure to attend.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.codemotion.com/magazine/dev-life/meet-the-codemotion-ambassadors/&quot;&gt;Codemotion ambassador program&lt;/a&gt; aims to create a structured Codemotion supporters network. Ambassadors are supported to share their software development knowledge, grow their professional skills, and provide value to the global tech community.&lt;/p&gt;
&lt;p&gt;Since I have been eagerly contributing to Codemotion during the last 8 years, it makes me really happy to be part of this group of people who can evangelize this community and make a bigger impact together on the overall tech community.&lt;/p&gt;
&lt;p&gt;I am particularly proud of one of the many initiatives I have been involved with as an ambassador: the &lt;em&gt;Wannabe speaker&lt;/em&gt; program, in which, every ambassador got the chance to help a first-time speaker to deliver a kick-ass presentation.&lt;/p&gt;
&lt;p&gt;I had the pleasure to work with &lt;strong&gt;Danilo Spinella&lt;/strong&gt; who presented a talk called &lt;a href=&quot;https://danyspin97.org/talks/beautiful_cli_apps_in_rust/&quot;&gt;Beautiful CLI Applications in Rust&lt;/a&gt;. You can &lt;a href=&quot;https://talks.codemotion.com/wannabe-speaker-1&quot;&gt;watch the recordings&lt;/a&gt; if you are curious (and you should).&lt;/p&gt;
&lt;p&gt;To be fair, Danilo did not need a lot of support and he was able to deliver an excellent and enjoyable presentation like a true veteran speaker!&lt;/p&gt;
&lt;p&gt;Also, I want to take this opportunity to thank &lt;a href=&quot;https://twitter.com/FrancescoSciuti&quot;&gt;Francesco Sciuti&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/maraexception/&quot;&gt;Mara Marzocchi&lt;/a&gt;, and the rest of the Codemotion team for adding me to this fantastic group of professionals. Ok, we are not always that &lt;em&gt;professionals&lt;/em&gt; but we definitely know how to have some fun!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“You cannot teach a man anything. You can only help him discover it within himself”&lt;/p&gt;
&lt;p&gt;— Galileo Galilei&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;public-speaking&quot;&gt;Public Speaking&lt;/h2&gt;
&lt;p&gt;I did not stop doing public speaking in 2022, so let’s have a look at a picture and then some stats.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Luciano Mammino Codemotion Ambassador at Codemotion Milan 2022&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;4096&quot; height=&quot;2731&quot; src=&quot;https://loige.co/_astro/luciano-mammino-loige-speaking-at-codemotion-milan-2022.C3AaWB0H_Z1eYume.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;This picture is from my talk at Codemotion Milan in October where I presented a talk called: &lt;a href=&quot;https://talks.codemotion.com/serverless-for-hpc&quot;&gt;“Serverless for High Performance Computing”&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In 2022, I spoke at &lt;strong&gt;25&lt;/strong&gt; different events and surpassed more than &lt;strong&gt;100&lt;/strong&gt; speaking engagements in total! Yeah, vanity metrics feel good sometimes! 😛&lt;/p&gt;
&lt;p&gt;Here’s the full list for 2022:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Migrate the monolith to the cloud&lt;/em&gt; on Fabio Biondi’s Twitch Channel (in Italian) (&lt;a href=&quot;https://loige.link/mono-cloud&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;A look inside the European Covid Green Pass&lt;/em&gt; at Rust Dublin Meetup (&lt;a href=&quot;https://loige.link/rust-green&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=2dFJkYH_Cc0&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Dal monolite al cloud: no stress!&lt;/em&gt; at Codemotion DevCast (in Italian) (&lt;a href=&quot;https://loige.link/mono-lit&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://talks.codemotion.com/dal-monolite-al-cloud-no-stress&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;The senior dev&lt;/em&gt; at Private event (&lt;a href=&quot;https://loige.link/senior&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Happy days with Node.js streams&lt;/em&gt; workshop at CityJS London (&lt;a href=&quot;https://github.com/lmammino/streams-workshop&quot;&gt;Repository&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Finding a lost song with Node.js &amp;#x26; async iterators&lt;/em&gt; at private event (&lt;a href=&quot;https://loige.link/song-iter&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;AMA: Node.js design patterns, AWS e altre cose fantastiche&lt;/em&gt; live interview with Emanuele Bartolesi for UGIdotNET (in Italian) (&lt;a href=&quot;https://www.ugidotnet.org/tv/episodio/2950/Ask-Me-Anything/Node-js-design-patterns-AWS-e-altre-cose-fantastiche&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Teach Kelvin Your Thing: Node.js streams&lt;/em&gt; with Kelvin Omereshone (&lt;a href=&quot;https://www.youtube.com/watch?v=ldcfYB_mo6Q&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Finding a lost song with Node.js &amp;#x26; async iterators&lt;/em&gt; at Node.js Global Summit (&lt;a href=&quot;https://loige.link/async-iter-song&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://youtu.be/cTD4KWSTEd8&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Javascript iteration protocols&lt;/em&gt; workshop at Codemotion Workshop Fest (&lt;a href=&quot;https://github.com/lmammino/iteration-protocols-workshop&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Let’s build a Serverless e-commerce from scratch&lt;/em&gt; workshop at CityJS Athens (&lt;a href=&quot;https://fth.link/sec&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Finding a lost song with Node.js &amp;#x26; async iterators&lt;/em&gt; at CityJS Athens (&lt;a href=&quot;https://slides.com/lucianomammino/finding-a-lost-song-with-node-js-and-async-iterators-cityjs&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Serverless for HPC&lt;/em&gt; at AWS Dublin Meetup (&lt;a href=&quot;https://slides.com/lucianomammino/serverless-for-hpc&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Async JavaScript and Node.js Design Patterns&lt;/em&gt; at Sailsconf (&lt;a href=&quot;https://slides.com/lucianomammino/async-javascript-and-nodejs-design-patterns&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=lxi8W7Z07To&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Interview with Reconfigured podcast&lt;/em&gt; (&lt;a href=&quot;https://www.youtube.com/watch?v=23bKVdY0gp8&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Building an invite-only microsite with Next.js &amp;#x26; Airtable&lt;/em&gt; at React Dublin Meetup (&lt;a href=&quot;https://loige.link/microsite&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;JavaScript Iteration Protocols&lt;/em&gt; workshop at NodeConfEU (&lt;a href=&quot;https://loige.link/lets-iter&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://github.com/lmammino/iteration-protocols-workshop&quot;&gt;Repository&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Serverless for High Performance Computing&lt;/em&gt; at Codemotion Milan (&lt;a href=&quot;https://fth.link/cm22&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://talks.codemotion.com/serverless-for-hpc&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Serverless for High Performance Computing&lt;/em&gt; at Cloud Day (&lt;a href=&quot;https://fth.link/cd22&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Come sviluppare una carriera in tech&lt;/em&gt; inteview with NonCompila on Twitch (in Italian) (&lt;a href=&quot;https://www.twitch.tv/videos/1647170014&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Full Stack Developer Creating Content&lt;/em&gt; interview with Zak Aghbal for the Content Creator Life Podcast (&lt;a href=&quot;https://www.youtube.com/watch?v=9C-akUL8Dw4&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Let’s build a 0-cost invite-only website with Next.js and Airtable&lt;/em&gt; at Conf42 JavaScript (&lt;a href=&quot;https://loige.link/micro42&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=2Spu3SQSMjQ&amp;#x26;t=703s&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Everything I know about S3 pre-signed URLs&lt;/em&gt; at AWS User Group Dublin Meetup (&lt;a href=&quot;https://fth.link/presign&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;From Node.js To Design Patterns&lt;/em&gt; at BuildPiper Meetup (&lt;a href=&quot;https://loige.link/node2dp&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=GVe9Ih47pm4&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Building an invite-only microsite with Next.js &amp;#x26; Airtable&lt;/em&gt; at React Milano (in Italian) (&lt;a href=&quot;https://loige.link/pizzaparty&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=WFd_W_PxBOE&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are curious to see all my other speaking engagements, I keep the complete list in the &lt;a href=&quot;/speaking&quot;&gt;speaking section&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you are brave enough to withstand my accent, you can &lt;a href=&quot;http://loige.link/invite-me-to-a-conference&quot;&gt;invite me to speak at one of your events&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“All life is problem solving”&lt;/p&gt;
&lt;p&gt;— Karl Popper&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;aws-bites&quot;&gt;AWS Bites&lt;/h2&gt;
&lt;p&gt;In 2022, Eoin Shanaghy and I produced &lt;strong&gt;45 new episodes&lt;/strong&gt; of &lt;a href=&quot;https://awsbites.com/&quot;&gt;AWS Bites&lt;/a&gt;, a weekly podcast where we discuss interesting AWS-related topics.&lt;/p&gt;
&lt;p&gt;“&lt;a href=&quot;https://awsbites.com/58-what-can-kitties-teach-us-about-aws/&quot;&gt;What can kitties teach us about AWS&lt;/a&gt;” is probably my favorite episode so far:&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em; margin-top: 2em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://www.youtube.com/embed/DYryFM1vTe0&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;I don’t really know if it’s the best episode to date, but certainly, it is the one with the best thumbnail! 😼&lt;/p&gt;
&lt;p&gt;One cool thing we did for AWS Bites is that this year we tried to build an actual product from scratch in a series of live streams. We built a minimal but functional clone of Dropbox transfer or WeTransfer and we did that by using serverless technologies on AWS.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Screenshot of Luciano Mammino and Eoin Shanaghy live coding a serverless file transfer application on AWS&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;485&quot; src=&quot;https://loige.co/_astro/eoin-shanaghy-and-luciano-mammino-live-coding-file-transfer-application-aws-bytes.CNcQHatA_Z1ov6Nl.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;The playlist with the recording of the live streams is available on YouTube: &lt;a href=&quot;https://www.youtube.com/playlist?list=PLAWXFhe0N1vI1_z-06EzJ22pz95_gBrId&quot;&gt;Live coding a serverless file transfer app on AWS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, it is worth mentioning that we surpassed &lt;strong&gt;1000 subscribers&lt;/strong&gt; on Youtube and that we also got some awesome stats from &lt;a href=&quot;https://open.spotify.com/show/3Lh7PzqBFV6yt5WsTAmO5q&quot;&gt;our Podcast on Spotify&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;statistics from Spotify Wrapped 2022 for AWS Bites podcasts&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1600&quot; height=&quot;1600&quot; src=&quot;https://loige.co/_astro/spotify-wrapped-aws-bites-2022.CjZV90Je_nsI6q.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;The episode count somehow does not match exactly what we have done, but all the other stats are more impressive than we expected. Let’s assume these stats are somewhat accurate and let’s celebrate… I guess. 🍻&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Success is not final, failure is not fatal: It is the courage to continue that counts”&lt;/p&gt;
&lt;p&gt;– Winston Churchill&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;live-coding-on-twitch&quot;&gt;Live coding on Twitch&lt;/h2&gt;
&lt;p&gt;Throughout 2022 I kept &lt;a href=&quot;https://twitch.tv/loige&quot;&gt;streaming on Twitch&lt;/a&gt; quite consistently. As I did last year, most of it was about solving Advent of Code challenges and learning Rust with my friends &lt;a href=&quot;https://twitter.com/88_eugen&quot;&gt;Eugen&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/gbinside&quot;&gt;Roberto&lt;/a&gt; (thanks a lot for being there, having fun, and learning with me).&lt;/p&gt;
&lt;p&gt;We streamed &lt;strong&gt;36 times&lt;/strong&gt; in total (almost once every week). Here are some more nerdy stats:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Twitch yearly recap 2022 for loige&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1332&quot; height=&quot;1330&quot; src=&quot;https://loige.co/_astro/twitch-loige-recap-2022.BcBnp-QW_Z1WKTcU.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;I am not at the levels of &lt;a href=&quot;https://www.twitch.tv/theprimeagen&quot;&gt;ThePrimeagen&lt;/a&gt;, but hey we had a lot of fun and I certainly learned a lot!&lt;/p&gt;
&lt;p&gt;Towards the end of the year, we also spent a bit of time learning &lt;a href=&quot;https://bevyengine.org/&quot;&gt;Bevy&lt;/a&gt;, a game engine written in Rust and built some game prototypes with it.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Building a game in Rust using Bevy, live stream on Twitch&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1361&quot; height=&quot;713&quot; src=&quot;https://loige.co/_astro/making-a-game-in-rust-with-bevy-loige.CA6ozgs5_58qoq.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;If you want to watch the recordings of these live experiments, here’s a YouTube playlist: &lt;a href=&quot;https://www.youtube.com/pla%5Blabel%5D(https://nodejsdesignpatterns.com/)ylist?list=PLbNOKnE-Oyr3yVKPvMeX0tKaalvafYQ8P&quot;&gt;Rust gamedev with Bevy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A big shout-out goes to &lt;a href=&quot;https://twitter.com/AlleviTommaso&quot;&gt;Tommaso Allevi&lt;/a&gt;, for helping us kickstart this journey into Rust gamedev. I have to say I really like the ECS (Entity Component System) model of Bevy so far, so I look forward to &lt;em&gt;playing&lt;/em&gt; more with it!&lt;/p&gt;
&lt;p&gt;Finally, I have been experimenting a bit with OBS and did a solo stream where I played a bit with &lt;a href=&quot;https://www.solidjs.com/&quot;&gt;Solid.js&lt;/a&gt; a frontend JavaScript framework that I am liking a lot and that I’d like to use more.&lt;/p&gt;
&lt;p&gt;All the recordings of &lt;a href=&quot;https://youtube.com/loige&quot;&gt;my live streams are available on YouTube&lt;/a&gt;, so make sure to give me a follow there!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Play is the work of the child”&lt;/p&gt;
&lt;p&gt;— Maria Montessori&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;nodejs-design-patterns&quot;&gt;Node.js Design Patterns&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://nodejsdesignpatterns.com&quot;&gt;Node.js Design Patterns&lt;/a&gt;, the book I co-authored with &lt;a href=&quot;https://twitter.com/mariocasciaro&quot;&gt;Mario Casciaro&lt;/a&gt;, is still trending quite well after 2.5 years since the third edition was published.&lt;/p&gt;
&lt;p&gt;The thing that makes me really happy is that the book keeps receiving very positive reviews. We doubled them since last year while keeping an incredibly high average rating of &lt;strong&gt;4.6&lt;/strong&gt;/5.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nodejsdesignpatterns.com&quot;&gt;&lt;img alt=&quot;Reviews for Node.js Design Patterns on Amazon.com&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;652&quot; height=&quot;511&quot; src=&quot;https://loige.co/_astro/node-js-design-patterns-reviews-2022.YAMfxW-w_ZAhBGH.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;At the time of writing the book is trending at:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;#110,173 in the global list&lt;/strong&gt; of Amazon books&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;#11 in the Web Services&lt;/strong&gt; category&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;#22 in the JavaScript&lt;/strong&gt; category&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We also keep receiving spontaneous comments and seeing &lt;a href=&quot;https://www.reddit.com/r/node/comments/yyu5xj/comment/iwx4o2n/?context=3&quot;&gt;random Reddit comments&lt;/a&gt; about how the book has been useful to readers.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Spontaneous feedback about Node.js Design Patterns by a reader&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;600&quot; height=&quot;396&quot; src=&quot;https://loige.co/_astro/node-js-design-patterns-book-luciano-mammino-mario-casciaro-twitter-feedback.DMHcap4h_1A88Bl.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;It seems like the book is even being used as teaching material in some universities… and someone even contacted us to say that they discovered this book in the library of a tech investment fund in San Francisco. 🤯&lt;/p&gt;
&lt;p&gt;Node.js Design Patterns keeps feeling like one of my biggest achievements professionally and I am always grateful to Mario for involving me in this awesome project.&lt;/p&gt;
&lt;p&gt;The book still feels quite relevant and up-to-date (updated to Node.js 14 and using ESM throughout), so I don’t feel like it’s time for a new edition just yet.&lt;/p&gt;
&lt;p&gt;If you disagree, do let me know. I’d love to hear your opinion!&lt;/p&gt;
&lt;p&gt;Finally a HUGE shout out to my dear friend &lt;a href=&quot;https://twitter.com/Dominus_Kelvin&quot;&gt;Kelvin Omereshone&lt;/a&gt; for gifting copies of the book to quite a few people! ❤️&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“A book is a garden, an orchard, a storehouse, a party, a company by the way, a counselor, a multitude of counselors”&lt;/p&gt;
&lt;p&gt;— Charles Baudelaire&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;fullstack-bulletin&quot;&gt;FullStack Bulletin&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://fullstackbulletin.com/&quot;&gt;FullStack bulletin&lt;/a&gt; is a free weekly newsletter about full stack web development. I have been running this project with my dear friend &lt;a href=&quot;https://twitter.com/andreaman87&quot;&gt;Andrea Mangano&lt;/a&gt; for the last 5 years.&lt;/p&gt;
&lt;p&gt;The achievement of 2022 is that we surpassed &lt;strong&gt;300 issues&lt;/strong&gt; and &lt;strong&gt;2500 subscribers&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;FullStack bulletin is always looking for sponsors, so if you like this format and you would like to reach a vetted audience of full stack engineers please &lt;a href=&quot;https://fstack.link/sponsor&quot;&gt;consider sponsoring us&lt;/a&gt;!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“The art of art, the glory of expression and the sunshine of the light of letters, is simplicity”&lt;/p&gt;
&lt;p&gt;— Walt Whitman&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;middy&quot;&gt;Middy&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://middy.js.org&quot;&gt;Middy&lt;/a&gt; is a Node.js middleware framework for AWS Lambda. I have been working on this project since the early days of Lambda (even though the first public commit was only made on the 3rd of August 2017).&lt;/p&gt;
&lt;p&gt;With that being said, I can’t really claim anything for the success of the framework during the last three years. Insted all the credit goes to Will Farrell, who has been relentlessly maintaining the framework, and to the amazing community behind Middy!&lt;/p&gt;
&lt;p&gt;The main news is that Middy v4 was published this year bringing significant innovation including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Support for Node.js 18&lt;/li&gt;
&lt;li&gt;Adoption of the new modular AWS SDK v3&lt;/li&gt;
&lt;li&gt;Better support for ESM&lt;/li&gt;
&lt;li&gt;Various performance improvements and bug fixes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/middyjs/middy/releases/tag/4.0.0&quot;&gt;&lt;img alt=&quot;Middy v4.0.0 published in 2022&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1600&quot; height=&quot;900&quot; src=&quot;https://loige.co/_astro/middy4_0_0_announcement.ff5dRMiN_GwnWs.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Middy has been growing even more in 2022, here is a shiny graph to prove it:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://npmtrends.com/@middy/core-vs-middy&quot;&gt;&lt;img alt=&quot;Middy Node.js Lambda middleware framework downloads 2022&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1317&quot; height=&quot;530&quot; src=&quot;https://loige.co/_astro/middy-weekly-downloads-growth-from-2021-to-2022.CCN3iG9B_29oono.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This graph shows the number of weekly downloads and it clearly highlights that the amount is more than doubled from the previous year!&lt;/p&gt;
&lt;p&gt;Note that &lt;code&gt;@middy/core&lt;/code&gt; represents newer versions (from v1 to v4), while &lt;code&gt;middy&lt;/code&gt; is the legacy 0.x package (surprisingly still being used a lot).&lt;/p&gt;
&lt;p&gt;If we look at the total number of downloads throughout the year we surpassed &lt;strong&gt;more than 8 million downloads&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://npm-stat.com/charts.html?package=%40middy%2Fcore&amp;#x26;package=middy&amp;#x26;from=2022-01-01&amp;#x26;to=2022-12-31&quot;&gt;&lt;img alt=&quot;Total number of downloads for Middy in 2022&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;538&quot; height=&quot;142&quot; src=&quot;https://loige.co/_astro/middy-total-number-of-downloads-2022.DCNrw88h_1WizUo.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I look forward to checking these stats again next year!&lt;/p&gt;
&lt;p&gt;Meanwhile, if you use Middy, make sure to &lt;a href=&quot;https://github.com/sponsors/willfarrell&quot;&gt;support Will Farrell for his awesome open-source work&lt;/a&gt; (yes, you should consider donating on GitHub)!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“If you want to heal your soul, ride a Vespa instead of driving a car”&lt;/p&gt;
&lt;p&gt;— anonymous&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;articles&quot;&gt;Articles&lt;/h2&gt;
&lt;p&gt;In 2022, I wasn’t really a prolific author on this blog. I published only 2 articles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/invite-only-microsites-with-nextjs-and-airtable&quot;&gt;Invite-only microsites with Next.js and AirTable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://loige.co/aws-solution-architect-professional-exam-notes-tips&quot;&gt;AWS Solution Architect Professional exam, my notes and tips&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On the other end, I think I was quite prolific in other media. Below there’s a full list, but the most important ones in terms of authority are definitely &lt;strong&gt;AWS&lt;/strong&gt; and &lt;strong&gt;InfoQ&lt;/strong&gt;! Both feel like massive achievements on their own!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://fourtheorem.com/what-do-you-need-to-know-about-sqs/&quot;&gt;What do you need to know about SQS?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nodejsdesignpatterns.com/blog/node-js-stream-consumer/&quot;&gt;Node.js stream consumer utilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fourtheorem.com/what-can-you-do-with-eventbridge/&quot;&gt;What can you do with EventBridge&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fourtheorem.com/what-do-you-need-to-know-about-sns/&quot;&gt;What do you need to know about SNS?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.infoq.com/articles/cloud-migrate-scale/&quot;&gt;A Recipe to Migrate and Scale Monoliths in the Cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aws.amazon.com/blogs/hpc/a-serverless-architecture-for-high-performance-financial-modelling/&quot;&gt;A serverless architecture for high performance financial modelling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sprkl.dev/quality-code-node-js-design-patterns-and-performance/&quot;&gt;Quality code: Node.js design patterns and performance (interview with Sprkl part I)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sprkl.dev/quality-code-node-js-design-patterns-and-dependency-management/&quot;&gt;Quality code: Node.js design patterns and dependency management (interview with Sprkl part II)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;“Every secret of a writer’s soul, every experience of his life, every quality of his mind, is written large in his works”&lt;/p&gt;
&lt;p&gt;— Virginia Woolf&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;open-source&quot;&gt;Open Source&lt;/h2&gt;
&lt;p&gt;In 2022 I continued steadily to do some degree of open source work by contributing to existing repositories and starting new ones.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/lmammino?tab=overview&amp;#x26;from=2022-12-01&amp;#x26;to=2022-12-19&quot;&gt;&lt;img alt=&quot;GitHub contribution graph for Luciano Mammino (lmammino)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;851&quot; height=&quot;220&quot; src=&quot;https://loige.co/_astro/lmammino-github-contribution-graph-2022.CVgDNteH_HA9IJ.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here’s a list of the most meaningful contributions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/tall&quot;&gt;&lt;code&gt;lmammino/tall&lt;/code&gt;&lt;/a&gt; - a Promise-based, No-dependency URL unshortner (expander) module for Node.js. I have been working with &lt;a href=&quot;https://github.com/karlhorky&quot;&gt;Karl Horky&lt;/a&gt; to make the library extensible and to add some advanced plugins.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/rust-advent&quot;&gt;&lt;code&gt;lmammino/rust-advent&lt;/code&gt;&lt;/a&gt; - the repository where we publish all our Rust solutions for Advent of Code.&lt;/li&gt;
&lt;li&gt;I contributed to &lt;a href=&quot;https://github.com/aws-samples/serverless-patterns&quot;&gt;&lt;code&gt;aws-samples/serverless-patterns&lt;/code&gt;&lt;/a&gt; with a &lt;a href=&quot;https://github.com/aws-samples/serverless-patterns/pull/449&quot;&gt;small fix&lt;/a&gt; that leverages the streaming capabilities of &lt;code&gt;sharp&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I created &lt;a href=&quot;https://github.com/lmammino/mega-match-vs-phf&quot;&gt;a repository&lt;/a&gt; to benchmark the performance of &lt;a href=&quot;https://docs.rs/phf/latest/phf/&quot;&gt;&lt;code&gt;phf&lt;/code&gt;&lt;/a&gt;, a Rust library using perfect hash functions to generate build-time hash tables, against a mega-match expression.&lt;/li&gt;
&lt;li&gt;I delivered a talk called “The Senior Dev” and since I decided to use &lt;a href=&quot;https://sli.dev/&quot;&gt;&lt;code&gt;slidev&lt;/code&gt;&lt;/a&gt; to generate my slides, I hosted the &lt;a href=&quot;https://github.com/lmammino/the-senior-dev&quot;&gt;source code for the slides&lt;/a&gt; on GitHub.&lt;/li&gt;
&lt;li&gt;I created &lt;a href=&quot;https://github.com/fourTheorem/api-gateway-sls-example&quot;&gt;&lt;code&gt;fourTheorem/api-gateway-sls-example&lt;/code&gt;&lt;/a&gt;, an example of how to build a simple API with API Gateway, Lambda and the serverless framework.&lt;/li&gt;
&lt;li&gt;Thanks to my open source work on &lt;a href=&quot;https://github.com/lmammino/iteration-protocols-workshop&quot;&gt;lmammino/iteration-protocols-workshop&lt;/a&gt;, I had the pleasure to be invited to &lt;a href=&quot;https://github.com/mdn/content/pull/17529&quot;&gt;review a PR&lt;/a&gt; that adds &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator&quot;&gt;Async generator documentation to MDN&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I developed a repository called &lt;a href=&quot;https://github.com/lmammino/secret-pizza-party&quot;&gt;&lt;code&gt;lmammino/secret-pizza-party&lt;/code&gt;&lt;/a&gt;, a sample Next.js website to showcase how you can make invite-only SPAs with Next.js, AirTable &amp;#x26; Vercel.&lt;/li&gt;
&lt;li&gt;I worked with the awesome &lt;a href=&quot;https://github.com/vorillaz&quot;&gt;Theodore Vorillas&lt;/a&gt; and submitted a couple of PRs to improve &lt;a href=&quot;https://github.com/proximahq/clickhouse&quot;&gt;&lt;code&gt;proximahq/clickhouse&lt;/code&gt;&lt;/a&gt;, a simple, plain, efficient Clickhouse client.&lt;/li&gt;
&lt;li&gt;I worked with Eoin Shanaghy on &lt;a href=&quot;https://github.com/awsbites/weshare.click&quot;&gt;&lt;code&gt;awsbites/weshare.click&lt;/code&gt;&lt;/a&gt;, an example personal file transfer app on AWS.&lt;/li&gt;
&lt;li&gt;During NodeConf EU I attended a fantastic workshop by &lt;a href=&quot;https://twitter.com/pattyneta&quot;&gt;Patty O’Callaghan&lt;/a&gt; about &lt;a href=&quot;https://www.tensorflow.org/js&quot;&gt;tensorflow.js&lt;/a&gt; and, as a result of what I learned, I developed a sample application that you can find in &lt;a href=&quot;https://github.com/lmammino/crappy-object-recognition-web-app&quot;&gt;&lt;code&gt;lmammino/crappy-object-recognition-web-app&lt;/code&gt;&lt;/a&gt; (screenshot below).&lt;/li&gt;
&lt;li&gt;During NodeConf EU I also collected all my notes in a &lt;a href=&quot;https://github.com/lmammino/nodeconfeu2022-notes&quot;&gt;repository&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I created a &lt;a href=&quot;https://github.com/lmammino/expenses&quot;&gt;simple script that helps me with tracking my expenses for tax reasons&lt;/a&gt;. I am not a tax expert, but you can take a look and adapt it to your particular use cases (while making sure to consult your accountant)!&lt;/li&gt;
&lt;li&gt;I have created several repositories with my Rust Bevy experiments: &lt;a href=&quot;https://github.com/lmammino/bevy-wrapping-square&quot;&gt;&lt;code&gt;lmammino/bevy-wrapping-square&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/lmammino/stranded-in-space&quot;&gt;&lt;code&gt;lmammino/stranded-in-space&lt;/code&gt;&lt;/a&gt;, and &lt;a href=&quot;https://github.com/lmammino/bevy-fuel-tank&quot;&gt;&lt;code&gt;lmammino/bevy-fuel-tank&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I also created &lt;a href=&quot;https://github.com/lmammino/nannou-sand-simulation&quot;&gt;a Rust repository&lt;/a&gt; with my experiments with &lt;a href=&quot;https://nannou.cc/&quot;&gt;Nannou&lt;/a&gt;, an open-source creative-coding toolkit for Rust.&lt;/li&gt;
&lt;li&gt;I started solving Advent of Vue challenges but using Solid.js instead and I am keeping my code in this repository: &lt;a href=&quot;https://github.com/lmammino/advent-of-solidjs&quot;&gt;lmammino/advent-of-solidjs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I created a &lt;a href=&quot;https://github.com/lmammino/etna-facts&quot;&gt;simple repository&lt;/a&gt; that can be used as a library and an API to get facts about Mount Etna (the volcano close to where I am from in Sicily).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/lmammino/crappy-object-recognition-web-app&quot;&gt;&lt;img alt=&quot;A screenshot of my crappy object detection app built using tensorflow.js&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;800&quot; height=&quot;622&quot; src=&quot;https://loige.co/_astro/screenshot-for-lmammino-crappy-object-recognition-web-app.Cb24uwUf_Z1io3FM.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Above a screenshot of my &lt;a href=&quot;https://github.com/lmammino/crappy-object-recognition-web-app&quot;&gt;crappy object recognition application&lt;/a&gt; built with Tensorflow.js and Solid.js. I am also about &lt;em&gt;70% sure&lt;/em&gt; that I am a real person! 😆&lt;/p&gt;
&lt;p&gt;A final mention is my &lt;a href=&quot;https://github.com/nodesecurity/eslint-plugin-security/pull/95&quot;&gt;open PR&lt;/a&gt; together with &lt;a href=&quot;https://twitter.com/simonesanfradev&quot;&gt;Simone Sanfratello&lt;/a&gt; where we are trying to bring the awesome &lt;a href=&quot;https://github.com/lirantal/anti-trojan-source/&quot;&gt;&lt;code&gt;anti-trojan-source&lt;/code&gt;&lt;/a&gt; detector by &lt;a href=&quot;https://twitter.com/liran_tal&quot;&gt;Liran Tal&lt;/a&gt; directly into &lt;a href=&quot;https://github.com/nodesecurity/eslint-plugin-security&quot;&gt;&lt;code&gt;nodesecurity/eslint-plugin-security&lt;/code&gt;&lt;/a&gt;. I hope this will be merged before the end of 2022!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Perseverance is not a long race; it is many short races one after the other”&lt;/p&gt;
&lt;p&gt;— Walter Elliot&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;random-stuff&quot;&gt;Random stuff&lt;/h2&gt;
&lt;p&gt;And as we get ready to wrap things up, here are a few more random things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Last year, I became a &lt;strong&gt;Certified AWS Solution Architect Professional&lt;/strong&gt;. If you are curious to know what was my experience and get some of my study notes, make sure to check out my article &lt;a href=&quot;https://loige.co/aws-solution-architect-professional-exam-notes-tips&quot;&gt;AWS Solution Architect Professional exam, my notes and tips&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I got married to the most wonderful person in the world (and this alone makes 2022 the best year ever)! 👰‍♀️❤️🤵‍♂️&lt;/li&gt;
&lt;li&gt;I Restarted BJJ training (and after almost 3 years it feels like I have to re-learn everything from scratch)!&lt;/li&gt;
&lt;li&gt;I kept running, running a total of &lt;strong&gt;340 Km&lt;/strong&gt;… 🏃‍♂️ And once again big thanks to my friend &lt;a href=&quot;https://twitter.com/lucamarchesotti&quot;&gt;Luca Marchesotti&lt;/a&gt; for motivating me.&lt;/li&gt;
&lt;li&gt;I got covid… twice! 🤧&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;expectations-for-next-year&quot;&gt;Expectations for next year&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Oh My God animation with an owl&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;320&quot; height=&quot;220&quot; src=&quot;https://loige.co/_astro/omg.mkZx-Rrq_Z2eAGmM.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;OMG, are you still here?! I am seriously impressed. 🥸&lt;/p&gt;
&lt;p&gt;At this point, you should go the extra mile and make sure to leave me a &lt;a href=&quot;#comments&quot;&gt;comment&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Ok, before we wrap things up, let me tell you what’s my plan for 2023.&lt;/p&gt;
&lt;p&gt;Well… there is no big plan, really!&lt;/p&gt;
&lt;p&gt;My overall goal is to keep growing my expertise in &lt;strong&gt;AWS&lt;/strong&gt; and &lt;strong&gt;Serverless&lt;/strong&gt; and work on interesting projects. Luckily there is no shortage of opportunities when working with fourTheorem, so I feel this goal will be pretty much achievable organically by just keep doing what I do in my daily work.&lt;/p&gt;
&lt;p&gt;I’d also love to have an opportunity to put all the &lt;strong&gt;Rust&lt;/strong&gt; learnings of the last 4 years into something a bit more practical, or &lt;strong&gt;production-ready&lt;/strong&gt; if you will! If a work project does not manifest itself I might try to get a bit more serious with my side projects and maybe try to build something more involved in Rust. I will most likely continue some game dev sessions in my streams, but I might also try to do something that combines Rust with AWS, possibly including Serverless. I have been experimenting with Rust lambdas and I have been blown away by the performance, so there’s an opportunity there.&lt;/p&gt;
&lt;p&gt;Finally, I have been quite excited by &lt;strong&gt;Solid.js&lt;/strong&gt;, so I’ll be seeking new opportunities to play with it!&lt;/p&gt;
&lt;p&gt;Of course, I’ll try my best to keep pushing things that I have been investing in the last few years: AWS Bites, FullStack bulletin and live coding on Twitch. I will try to find other opportunities for content creation, most likely publishing articles and delivering talks at conferences.&lt;/p&gt;
&lt;p&gt;If you have any suggestions or comments on this &lt;em&gt;obviously perfect&lt;/em&gt; plan, I am all ears!&lt;/p&gt;
&lt;p&gt;I’d also love to know what was your biggest achievement of 2022 and what you plan to accomplish in 2023, so don’t be shy and leave a comment!&lt;/p&gt;
&lt;p&gt;This is me, signing out and getting ready for 2023!&lt;/p&gt;
&lt;p&gt;Until next time, peace! 👋&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/2022-a-year-in-review.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/2022-a-year-in-review.png" width="1200" height="630"/></media:content><category>life</category><author>Luciano Mammino</author><comments>https://loige.co/2022-a-year-in-review/#comments</comments><enclosure url="https://loige.co/og/2022-a-year-in-review.png" length="0" type="image/png"/></item><item><title>I am co-authoring a book about Rust and Lambda</title><link>https://loige.co/coauthoring-a-book-about-rust-and-lambda/</link><guid isPermaLink="true">https://loige.co/coauthoring-a-book-about-rust-and-lambda/</guid><description>Announcing Crafting Lambda Functions in Rust, a new book that guides you through building efficient, reliable, and cost-effective AWS Lambda functions using Rust, written by Luciano Mammino and James Eastham. Learn why Rust and serverless are a perfect match. Early access is now available at rust-lambda.com!</description><pubDate>Mon, 16 Dec 2024 09:30:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m beyond excited to share some big news with you: I’m co-authoring a new book
called &lt;em&gt;Crafting Lambda Functions in Rust&lt;/em&gt; together with the amazing
&lt;a href=&quot;https://jameseastham.co.uk/&quot;&gt;James Eastham&lt;/a&gt;! If you’re as passionate about
&lt;a href=&quot;/tag/serverless&quot;&gt;serverless&lt;/a&gt; and &lt;a href=&quot;/tag/serverless&quot;&gt;Rust&lt;/a&gt; as I am, you’ll want
to check this out. We even have an official website for it, check out
&lt;a href=&quot;https://rust-lambda.com&quot;&gt;the book Crafting Lambda Functions in Rust&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This book is your hands-on guide to building efficient, scalable, and
cost-effective serverless applications with AWS Lambda functions and using the
power of the Rust programming language.&lt;/p&gt;
&lt;h2 id=&quot;how-it-all-started&quot;&gt;How it all started&lt;/h2&gt;
&lt;p&gt;The idea for this book didn’t happen overnight. It all began when I kept
crossing paths with James at conferences over the years. Every time we met, we’d
end up deep in conversation about two of our favorite topics: &lt;strong&gt;serverless
computing&lt;/strong&gt; and &lt;strong&gt;Rust&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This year, at Rust Nation in London, the stars seemed to align. We realized that
we had both been toying with the idea of writing a book to share what we’d
learned about building AWS Lambda functions in Rust. We talked about how Rust is
not only incredibly powerful for Lambda but also surprisingly easy (perhaps
unexpectedly) to get started with. Rust has a reputation of being hard to grasp,
so it might come as a surprise to many to discover that building Lambda
functions with this language it’s a very accessible endeavor. While we were
debating different approaches we had played with and discussing the current
tooling ecosystem, it became clear that a little evangelism could go a long way
in bringing this tech combo to a broader audience.&lt;/p&gt;
&lt;p&gt;At that point, joining forces felt like the most natural thing to do. We agreed
to tackle this project together, and what started as an idea is now becoming a
reality. And while we’re still knee-deep in writing, we hope that someday we’ll
look back and say, “And the rest is history!” For now, though, there’s a huge
pile of work ahead, and we’re ready to take it on.&lt;/p&gt;
&lt;p&gt;By the way, before you move on to find out more details about our motivations
and the book itself, I’d like to make it very clear that the book is already
available for purchase in early access. This means that you can start reading it
right now and help us shape the final version with your feedback. If you’re
interested, head over to
&lt;a href=&quot;https://rust-lambda.com&quot;&gt;Crafting Lambda Functions in Rust’s website&lt;/a&gt; to grab
your copy. And yes, at the time of writing it’s heavily discounted, so I’d like
to think you get yourself a bit of a good deal…&lt;/p&gt;
&lt;p&gt;Oh yeah, let me show you the book cover as well, so you can tell that this is
real!&lt;/p&gt;
&lt;div style=&quot;text-align:center; display: block; max-width: 400px; margin: 0 auto;&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://rust-lambda.com&quot;&gt;&lt;img alt=&quot;The cover of the book Crafting Lambda Functions in Rust&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;800&quot; height=&quot;1131&quot; src=&quot;https://loige.co/_astro/crafting-lambda-functions-in-rust-cover-light.DEnptqPX_Zj5vyc.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;small&gt;Yes, our mascot is a crab (a &lt;em&gt;cRustacean&lt;/em&gt;, get it?) with a Lambda hat…
If you have been wandering around this blog long enough you’d probably get the
video game reference as well!&lt;/small&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-rust-and-lambda&quot;&gt;Why Rust and Lambda?&lt;/h2&gt;
&lt;p&gt;I have actually written an entire blog post on this last year:
&lt;a href=&quot;/why-you-should-consider-rust-for-your-lambdas/&quot;&gt;Why you should consider Rust for your Lambdas&lt;/a&gt;.
But don’t worry, if you are in a rush, I’ll give you a quick summary here
anyway.&lt;/p&gt;
&lt;p&gt;The combination of Rust and AWS Lambda is a game changer. Over the past few
years, I’ve been using Rust to build serverless applications, and I’ve seen
firsthand how well they complement each other. Here’s why I think Rust is an
awesome choice for writing Lambda functions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cost Savings and Sustainability&lt;/strong&gt;: As a compiled language, Rust produces
highly efficient binaries that are compact and lightning-fast. This means your
Lambda functions run quicker, consume less memory, and ultimately cost less to
execute. Remember that with Lambda functions the &lt;em&gt;execution cost&lt;/em&gt; is given by
the formula &lt;code&gt;memoryCost * executionTime&lt;/code&gt; where &lt;code&gt;memoryCost&lt;/code&gt; is a price unit
that depends on how much memory you allocated for the Lambda and
&lt;code&gt;executionTime&lt;/code&gt; is how long that function has been executing in milliseconds.
With Rust, in most circumstances, you can lower both dimensions, compared to
interpreted languages such as JavaScript and Python. But it’s not just about
saving money: Rust’s efficiency reduces resource usage, which translates to a
lower carbon footprint. Your apps can be both cost-effective and
environmentally friendly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reliability and Correctness&lt;/strong&gt;: Rust’s strict compiler and type system are
like having an extra pair of eyes on your code. I am a big fan of the idea of
not having a &lt;code&gt;null&lt;/code&gt; type in the language and that you have to express the
potential absence of data using a dedicated wrapper type: the
&lt;a href=&quot;https://doc.rust-lang.org/std/option/enum.Option.html&quot;&gt;&lt;code&gt;Option&lt;/code&gt;&lt;/a&gt; type. The
same goes for the
&lt;a href=&quot;https://doc.rust-lang.org/std/result/enum.Result.html&quot;&gt;&lt;code&gt;Result&lt;/code&gt;&lt;/a&gt; type which
lets you deal with errors in a very explicit way. These features make it
easier to spot edge-cases as early as possible and you have to explicitly
decide how to handle them. Once you get used to these abstractions and
appreciated their benefits, you’ll find yourself being much more confident
that your code is correct and reliable. When you’re working in a serverless
environment where reliability is often non-negotiable, this is a huge win.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fast Starts, Smooth Runs&lt;/strong&gt;: With Rust, you get tiny package sizes and no
garbage collection. This often translates to faster cold starts. How fast you
might ask… What I have seen is something on the range of 10-60 ms (depending
on the amount of libraries and the amount of init work to be performed). This
is in the order of 10-20x of what I have generally observed with JavaScript
and Python. Now think about using Lambdas as your HTTP backend or for any
other task that has a user waiting for a response. This means that, even in
the occasional presence of a cold start, your users will barely notice any
additional delay which translates to a more seamless experience, even during
peak loads.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A Streamlined Developer Experience&lt;/strong&gt;: Last but definitely not least, we
should talk about DX. When I first talk to people about using Rust for Lambda
functions, most of them are initially skeptical. And I get it: although
fast-growing, Rust is still a relatively niche language, and it’s certainly
not common to see it being used with Lambda. Plus Rust has gotten a reputation
of being somewhat difficult to learn, so all of this creates an expectation
that, although there might be strong benefits, it must be real hard to write a
Lambda in Rust and bring it all the way to production. Now, we can argue about
Rust being difficult or not. I acknowledge there might be some initial
challenges when you come from languages that manage memory for you, but it’s
also fair to say that it isn’t that hard to start writing Rust and get
productive with it. You don’t need to become an all around expert of the
language to write decent code that be shipped to production. But this isn’t
the only point, because the real super power for the combo Rust-Lambda is a
tool called &lt;a href=&quot;https://cargo-lambda.info&quot;&gt;&lt;strong&gt;Cargo Lambda&lt;/strong&gt;&lt;/a&gt;. This tool makes it
super easy to scaffold a Lambda, test it locally, compile it and ship it to
production. It even integrates with most of IaC tools out there such as SAM,
Terraform and even CDK. This let’s you focus on writing great code while
letting the tooling handle the heavy lifting. I seriously wish a tool like
this existed also for Node.js and Python!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;early-access-read-and-shape-the-book&quot;&gt;Early Access: Read and Shape the Book!&lt;/h2&gt;
&lt;p&gt;If you got this far, hopefully, you are now convinced that using Rust for your
Lambda functions is not that crazy of an idea, so the next question is &lt;em&gt;how do
you get started&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;Well, that’s why we are writing this book, so you are in the right place!&lt;/p&gt;
&lt;p&gt;I have a bad and a good news though!&lt;/p&gt;
&lt;p&gt;The bad news is that the book isn’t finished (unless you are reading this a bit
ahead in the future). But, the good news is that everything we have produced so
far is already available and there’s a significant amount of work already!&lt;/p&gt;
&lt;p&gt;You can get your copy of the book right now in early access. This means you can
get started today! By purchasing early access, you’ll:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Receive chapters as they’re written&lt;/strong&gt;: You’ll get new content and updates
regularly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contribute to the book&lt;/strong&gt;: Share your feedback, help shape the final version,
and, if you like, get your name on the book!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enjoy a discounted price&lt;/strong&gt;: Early access comes at a (significantly) reduced
cost from what we are expecting the final cover price to be!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This approach lets us work collaboratively with readers to ensure the book is as
practical and comprehensive as possible.&lt;/p&gt;
&lt;p&gt;Is it worth to get the book right now? I don’t know, you tell us! 😅&lt;/p&gt;
&lt;p&gt;I’d like to think it is a good deal if you are looking to get started ASAP.&lt;/p&gt;
&lt;p&gt;Worth mentioning that what we have published so far includes &lt;strong&gt;6 chapters&lt;/strong&gt; that
will guide you from building a serious serverless application (a URL shortener
service) from scratch and ship it to production. This accounts for &lt;strong&gt;more than
100 pages&lt;/strong&gt; and tons of code examples and exercises.&lt;/p&gt;
&lt;h2 id=&quot;whats-in-and-what-will-be-in-the-book&quot;&gt;What’s in (and what will be in) the Book?&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;A diagram of a serverless architecture from AWS Application Composer&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1396&quot; height=&quot;778&quot; src=&quot;https://loige.co/_astro/serverless-architecture.DLMvpDl7_Z11p5F.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Here’s a list of the chapters of the book, giving you a clear roadmap of what’s
available and what’s coming:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chapter 1: Rust &amp;#x26; Lambda&lt;/strong&gt; (available): We’ll explore why using Rust and AWS
Lambda together is a great idea. We’ll discuss the benefits of this
combination compared to other alternatives.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chapter 2: A ‘Hello, Serverless’ API&lt;/strong&gt; (available): You’ll learn how to
write your first Rust-powered Lambda function. You’ll create a simple “Hello,
Serverless” API that demonstrates the basics of AWS Lambda and Rust.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chapter 3: Infrastructure as Code with SAM&lt;/strong&gt; (available): We’ll show you how
to deploy and manage your Rust Lambda functions using the Serverless
Application Model (SAM). You’ll learn how to create, update, and delete your
functions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chapter 4: Integrating with External Systems&lt;/strong&gt; (available): We’ll teach you
how to make arbitrary HTTP requests or interact with other AWS services from
your Lambda functions. We’ll cover various techniques for integrating with
external systems.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chapter 5: Code Organization&lt;/strong&gt; (available): This chapter will focus on best
practices for organizing the code for projects with multiple Lambda functions.
You’ll learn how to structure your code for maintainability and readability.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chapter 6: Making the Code Testable&lt;/strong&gt; (available): We’ll show you how to
structure your code in a way that allows you to write good tests for your
Lambda functions. You’ll learn about testing fundamentals and how they apply
to Rust Lambda functions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chapter 7: Handling Different Kinds of Events&lt;/strong&gt; (in progress): In this
chapter, we’ll discuss how to handle AWS-specific events, custom events, and
arbitrary JSON in a strongly-typed way. You’ll learn about event handling best
practices for your Rust Lambda functions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chapter 8: Different Ways of Writing Lambda Handlers&lt;/strong&gt; (in progress): We’ll
explore different ways to write your Lambda function handlers. We’ll cover
simple async functions, custom structs, and implementing the Tokio Tower
service trait.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chapter 9: Configuration Management and Handling Secrets&lt;/strong&gt; (planned): This
chapter will focus on best practices for injecting configuration and secrets
into your Rust Lambda functions. You’ll learn how to securely manage sensitive
data in your serverless applications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chapter 10: Observing All the Things&lt;/strong&gt; (planned): We’ll show you how to make
your Rust Lambda functions observable using CloudWatch or OpenTelemetry.
You’ll learn about monitoring best practices and how they apply to your
serverless functions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chapter 11: Middlewares&lt;/strong&gt; (planned): In this chapter, we’ll introduce the
middleware pattern and show you how to handle cross-cutting concerns in an
elegant and reusable way. You’ll learn about middleware best practices for
your Rust Lambda functions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chapter 12: Hosting Existing HTTP Services&lt;/strong&gt; (planned): We’ll teach you how
to wrap existing HTTP services in a Lambda function to make them easily
available as serverless functions. You’ll learn about the benefits and
trade-offs of using this approach.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chapter 13: Lambda Extensions&lt;/strong&gt; (planned): We’ll dive into writing Lambda
extensions using Rust.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chapter 14: Integrating with GitHub Actions&lt;/strong&gt; (planned): Learn how to
configure the integration between AWS and GitHub Actions to test, build, and
deploy your Lambda functions in an automated fashion.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Appendix A: IaC Alternatives&lt;/strong&gt; (planned): Discover how to use CDK or
Terraform as an alternative to SAM for managing your serverless
infrastructure.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This list isn’t set in stone! If you think there’s a big topic missing or
something you’d love to see covered, please let us know. We want to write the
book you’d like to read about using Rust with AWS Lambda!&lt;/p&gt;
&lt;h2 id=&quot;ready-to-start&quot;&gt;Ready to Start?&lt;/h2&gt;
&lt;p&gt;As we wrap up, it’s worth mentioning that this journey isn’t just about writing
AWS Lambda functions in Rust, but it’s about diving deep into the serverless
ecosystem. Along the way, we’ll explore DynamoDB, S3, EventBridge, and other
building blocks of serverless architecture, all while building a real,
production-ready application.&lt;/p&gt;
&lt;p&gt;And of course, this journey isn’t one you have to take alone. There’s a thriving
community waiting to support you, including
&lt;a href=&quot;https://discord.gg/w9CWQRHzjn&quot;&gt;our Discord server&lt;/a&gt;, where you can connect with
like-minded developers, ask questions, and share your experiences. Whether
you’re here for the Rust, the serverless insights, or the hands-on learning, I’m
glad to have you along for the ride.&lt;/p&gt;
&lt;p&gt;So, what are you waiting for? Dive in, experiment, and share your feedback.
Together, let’s redefine what’s possible with serverless and Rust. Head over to
&lt;a href=&quot;https://rust-lambda.com&quot;&gt;rust-lambda.com&lt;/a&gt; and start your journey today.&lt;/p&gt;
&lt;p&gt;Let’s build something amazing together!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/coauthoring-a-book-about-rust-and-lambda.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/coauthoring-a-book-about-rust-and-lambda.png" width="1200" height="630"/></media:content><category>rust</category><category>serverless</category><category>lambda</category><author>Luciano Mammino</author><comments>https://loige.co/coauthoring-a-book-about-rust-and-lambda/#comments</comments><enclosure url="https://loige.co/og/coauthoring-a-book-about-rust-and-lambda.png" length="0" type="image/png"/></item><item><title>2023 - A year in Review</title><link>https://loige.co/2023-a-year-in-review/</link><guid isPermaLink="true">https://loige.co/2023-a-year-in-review/</guid><description>In 2023, Luciano Mammino attended his first re:Invent, grew open source projects like Middy, continued podcasting on AWS Bites, and strengthened connections through public speaking and live coding. He also contributed to sustainability through LifeFoliage&apos;s Landscape Hunt game.</description><pubDate>Wed, 27 Dec 2023 15:00:00 GMT</pubDate><content:encoded>&lt;p&gt;2023: End of another year!&lt;/p&gt;
&lt;p&gt;Another year is gone and it’s time for another review of all the things I have accomplished professionally (and not) in 2023.&lt;/p&gt;
&lt;p&gt;I feel the usual disclaimer is mandatory here: I generally write these posts for myself and I don’t expect other people to read them. So this is going to be a long boring post and I hope that if you are willing to read through it you are doing it from the comfort of your bed and that it’s going to be a good read for you before falling asleep.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A cute dog rolling itself into a blanket over the word &amp;quot;Goodnight&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;400&quot; height=&quot;225&quot; src=&quot;https://loige.co/_astro/goodnight.BcgPF-HN_5Lokn.webp&quot; &gt;&lt;/p&gt;
&lt;h2 id=&quot;first-time-at-reinvent&quot;&gt;First time at re:Invent&lt;/h2&gt;
&lt;p&gt;It’s hard to pick what was my favourite thing of the year, but I want to start by sharing that 2023 marked my attendance of re:Invent. re:Invent is the biggest conference organized by AWS and it takes place every year in Las Vegas. It’s a huge event with more than 60k attendees and it’s a great opportunity to learn about the latest news from AWS and to meet a lot of people from the community.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Luciano Mammino at re:Invent 2023 in Las Vegas standing behind the writing &amp;quot;re:Invent&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;575&quot; src=&quot;https://loige.co/_astro/luciano-mammino-at-reinvent-2023.CD-0PVp9_Z1T2tHE.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;I admit I did not attend many talks but I managed to attend a few interesting ones and participate in different community events. This allowed me to focus on networking and meet so many amazing people from the community. I also had the opportunity to meet in person a lot of people I have been engaging with remotely for years and that was a great experience.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A collage of pictures of the people that Luciano Mammino met at re:Invent 2023&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;1024&quot; src=&quot;https://loige.co/_astro/luciano-mammino-reinvent-2023-mix-collage.CC_atlJq_Z2bDgAh.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;These are only a few of the many people I met! From the upper left: &lt;a href=&quot;https://twitter.com/andmoredev&quot;&gt;Andres Moreno&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/elchesco&quot;&gt;Franchesco Romero&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/mattbonig&quot;&gt;Matthew Bonig&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/astuyve&quot;&gt;AJ Stuyvenberg&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/alexbdebrie&quot;&gt;Alex DeBrie&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/AllenHeltonDev&quot;&gt;Allen Helton&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/jnardiello&quot;&gt;Jacopo Nardiello&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/bianchiluca&quot;&gt;Luca Bianchi&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/LatellaPaolo&quot;&gt;Paolo Latella&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/monicaontech&quot;&gt;Monica Colangelo&lt;/a&gt;, Mario &amp;#x26; Pacman, Allen Helton (again!), &lt;a href=&quot;https://twitter.com/lucamezzalira&quot;&gt;Luca Mezzalira&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/_JonMyer&quot;&gt;Jon Myer&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/dreamorosi&quot;&gt;Andrea Amorosi&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;These are really only a few of the many awesome folks you can meet in an event like re:Invent and I wish I had taken more pictures!&lt;/p&gt;
&lt;p&gt;I had the pleasure to be able to interview a few more people for an episode of &lt;a href=&quot;https://awsbites.com&quot;&gt;AWS Bites Podcast&lt;/a&gt; where I asked them questions such as “How to get started with AWS and Serverless”, “What is your favourite and least favourite thing about AWS”, “What’s your bold prediction for the future of serverless”, “Multi-cloud, yes or no?”, and, of course “What about AI? How is it going to change things?”.&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://www.youtube.com/embed/k7asMzLk9Jo&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;I also want to give a shout-out to a few folks who delivered some amazing talks that I’d recommend checking out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=1aTQI-Kqs2U&quot;&gt;Getting started building serverless event-driven applications (SVS205)&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/em__shea&quot;&gt;Emily Shea&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Mdh_2PXe9i8&quot;&gt;“Rustifying” serverless: Boost AWS Lambda performance with Rust (COM306)&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/TServerless&quot;&gt;EfiMerdler-Kravitz&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=6X4lSPkn4ps&quot;&gt;Advanced event-driven patterns with Amazon EventBridge (COM301-R)&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/sheenbrisals&quot;&gt;Sheen Brisals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=PVUofrFiS_A&quot;&gt;Advanced data modeling with Amazon DynamoDB (DAT410)&lt;/a&gt; by Alex DeBrie&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=2EDNcPvR45w&quot;&gt;Demystifying and mitigating AWS Lambda cold starts (COM305)&lt;/a&gt; by AJ Stuyvenberg&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Wzawix9bMAE&quot;&gt;Advanced AWS CDK: Lessons learned from 4 years of use (COM302)&lt;/a&gt; by Matthew Bonig&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In case you are curious, all the other talks are available on the official &lt;a href=&quot;https://www.youtube.com/@AWSEventsChannel&quot;&gt;AWS Events YouTube channel&lt;/a&gt;. There’s also a dedicated playlist for all the &lt;a href=&quot;https://www.youtube.com/playlist?list=PL2yQDdvlhXf_HQ1BmWQHoe1o5-SQMCUfl&quot;&gt;breakout session talks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A big thank you is mandatory to the AWS Hero program team: &lt;strong&gt;Taylor Jacobsen&lt;/strong&gt;, &lt;strong&gt;Farrah Campbell&lt;/strong&gt;, and &lt;strong&gt;Albert Zhao&lt;/strong&gt;. They did an amazing job at organizing the AWS Heroes Lounge and the AWS Heroes reception. They also did a great job at making sure that all the AWS Heroes had a great time at re:Invent and that we had the opportunity to meet and network with each other. I am really grateful for the opportunity to be part of this amazing program and I am looking forward to the next re:Invent!&lt;/p&gt;
&lt;p&gt;One last thing I want to mention is that re:Invent is a fantastic place for collaborating on content creation. I had the pleasure to collaborate with &lt;a href=&quot;https://twitter.com/mistwire&quot;&gt;Chriss Williams&lt;/a&gt; doing a &lt;a href=&quot;https://www.youtube.com/watch?v=ErJ8KpYd5B8&quot;&gt;quick interview&lt;/a&gt; for his &lt;a href=&quot;https://www.youtube.com/@vBrownBag&quot;&gt;vBrownBag channel&lt;/a&gt;. I also spoke with &lt;a href=&quot;https://twitter.com/julian_wood&quot;&gt;Julian Wood&lt;/a&gt; at their ServerlessLand booth (yet to be published) and with &lt;a href=&quot;https://www.linkedin.com/in/sam-complete-coding/&quot;&gt;Sam Williams&lt;/a&gt; from Complete Coding (yet to be published as well).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Life is beautiful not because of the things we see or do. Life is beautiful because of the people we meet.&lt;/p&gt;
&lt;p&gt;— Simon Sinek&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;middy&quot;&gt;Middy&lt;/h2&gt;
&lt;p&gt;Now, let’s talk a bit about &lt;a href=&quot;https://middy.js.org/&quot;&gt;Middy&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Middy is a Node.js middleware framework specifically designed for AWS Lambda! I’ve been part of this project since the early days of Lambda (even though the very first public commit only happened on August 3, 2017), and it’s been quite a journey.&lt;/p&gt;
&lt;p&gt;However, I must admit, I can’t take credit for the success of the framework over the last four years. All the kudos go to the dedicated efforts of &lt;a href=&quot;https://github.com/willfarrell&quot;&gt;Will Farrell&lt;/a&gt;, who has been tirelessly maintaining Middy, and of course, to the fantastic community that surrounds it!&lt;/p&gt;
&lt;p&gt;The biggest news for Middy this year are the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Secured a substantial sponsorship from &lt;a href=&quot;https://fourTheorem.com&quot;&gt;fourTheorem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Secured a significant sponsorship from &lt;strong&gt;AWS itself&lt;/strong&gt;! This is massive also because AWS is now officially endorsing Middy as a framework for building Lambda functions as part of their &lt;a href=&quot;https://docs.powertools.aws.dev/lambda/typescript/latest/&quot;&gt;AWS PowerTools suite&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Released a new major version: Middy v5.0!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;Middy v5.0 release banner&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1200&quot; height=&quot;675&quot; src=&quot;https://loige.co/_astro/middy-v5-release-banner.BiieXqpI_11XAod.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;I had the pleasure to contribute a bit to this new Major release by helping with improving the internal typings and by making some minor improvements to the website. I admit the TypeScript stuff was wild and I had to learn tons of tricks to make it work, but I am happy with the result and I am looking forward to contributing more to Middy in the future. A big thanks to all the people who helped through &lt;a href=&quot;https://github.com/middyjs/middy/pull/616/files&quot;&gt;this massive PR&lt;/a&gt;. The Middy community is awesome and this is a testament to how much you can learn and grow by contributing to open source projects.&lt;/p&gt;
&lt;p&gt;If you are using Middy and you want to know how to upgrade to V5, you can check out this dedicated &lt;a href=&quot;https://middy.js.org/docs/upgrade/4-5/&quot;&gt;Migration guide from Middy v4 to Middy v5&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But let’s talk numbers! Middy is constantly growing in its adoption, but how much?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://npmtrends.com/@codegenie/serverless-express-vs-@fastify/aws-lambda-vs-@middy/core-vs-@vendia/serverless-express-vs-aws-lambda-fastify-vs-aws-serverless-express-vs-lambda-api-vs-serverless-express-vs-serverless-http&quot;&gt;&lt;img alt=&quot;Adoption of Middy from the beginning of 2022 to the end of 2023 compared to other major frameworks&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1200&quot; height=&quot;473&quot; src=&quot;https://loige.co/_astro/middy-adoption-vs-other-frameworks-2022-2023.DU5GtLgu_ZxLfGv.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this graph we can see that, in 2023, Middy became the number one middleware framework for Lambda, surpassing &lt;a href=&quot;https://www.npmjs.com/package/@vendia/serverless-express&quot;&gt;&lt;code&gt;@vendia/serverless-express&lt;/code&gt;&lt;/a&gt;. If I have to guess this is because Middy is purely focused on Lambda and it doesn’t just try to adapt the HTTP-first Express paradigm to Lambda. The fact that &lt;code&gt;@vendia/serverless-express&lt;/code&gt; has been now moved to &lt;a href=&quot;https://www.npmjs.com/package/@codegenie/serverless-express&quot;&gt;&lt;code&gt;@codegenie/serverless-express&lt;/code&gt;&lt;/a&gt; might have been another contributing factor since the switch is fragmenting the data and most likely causing migration friction…&lt;/p&gt;
&lt;p&gt;If we zoom-in on the download numbers for Middy, the numbers, IMHO, look quite rewarding:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Total downloads of the year: almost &lt;strong&gt;18mln downloads&lt;/strong&gt; (core only) + almost &lt;strong&gt;78mln downloads&lt;/strong&gt; including all the other 35 supporting packages (&lt;a href=&quot;https://docs.google.com/spreadsheets/d/1zYddbgGfGcthN5BAeyYLDiKtVtCg7LPVptCtdetHNzc/edit?usp=sharing&quot;&gt;data&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;A peak of almost &lt;strong&gt;600k downloads/week&lt;/strong&gt; for Middy core&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://npm-stat.com/charts.html?package=%40middy%2Fcore&amp;#x26;from=2023-01-01&amp;#x26;to=2023-12-31&quot;&gt;&lt;img alt=&quot;Middy&amp;amp;#x27;s download per week in 2023&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1200&quot; height=&quot;464&quot; src=&quot;https://loige.co/_astro/middy-downloads-per-week-2023.Dkvw3Ujk_ZqGyS2.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If we look at some vanity metrics (GitHub stars count), there was some nice steady growth as well:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://starchart.cc/middyjs/middy&quot;&gt;&lt;img alt=&quot;Growth chart of the number of stars on GitHub&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2080&quot; height=&quot;942&quot; src=&quot;https://loige.co/_astro/middy-github-stars-growth-chart.bp2ZFcDu_2kXbFG.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We are so close to &lt;strong&gt;3600 stars&lt;/strong&gt;, so if you use Middy and find value in it, consider &lt;a href=&quot;https://github.com/middyjs/middy&quot;&gt;giving it a star on GitHub&lt;/a&gt; and help us reach this vanity milestone! 😋&lt;/p&gt;
&lt;p&gt;One final call to action: if you like Middy and care about its future, it would be only fair to &lt;a href=&quot;https://github.com/sponsors/willfarrell&quot;&gt;consider sponsoring Will Farrell on GitHub&lt;/a&gt;. He is the one who is putting most of the effort into maintaining the project and he is doing an amazing job at it. 🙏&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Side projects create the greatest companies because they begin as freedom machines, labors of love and truth vehicles. Precious time is traded to pursue something pure.&lt;/p&gt;
&lt;p&gt;— Brian Norgard&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;almost-3-years-at-fourtheorem&quot;&gt;Almost 3 years at FourTheorem&lt;/h2&gt;
&lt;p&gt;February next year will mark my third year as a Senior Architect at &lt;a href=&quot;https://fourTheorem.com&quot;&gt;fourTheorem&lt;/a&gt;. It’s crazy to think that, because I am still as happy as I was in the first few months which I admit is something fairly unusual for me since I have been a bit of a job-hopper before changing jobs regularly every ~2 years.  Now I am not just happy to stick around with fourTheorem, but I am also looking forward to years to come!&lt;/p&gt;
&lt;p&gt;If you ask me why, I probably wouldn’t have a straight answer. Or, at least, I wouldn’t be able to pinpoint a single factor that contributes to my happiness. I think it’s a combination of many things: great culture, interesting projects (always challenging and with lots of variety), amazing colleagues both at human and technical levels, and a lot of freedom to experiment and grow. Finally, I feel that the work we do is meaningful and has a positive impact on our customers and the community. And looking back at my career, I think this is something that is not obvious at all in the tech world.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;(most of) the team at fourTheorem on a day out in Dublin in front of a yellow bus&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;563&quot; src=&quot;https://loige.co/_astro/fourtheorem-team-2023.C3GAyADw_Z1i7aFl.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Most of the cheerful team at fourTheorem&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;Some of the things we have done in 2023:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Welcomed 2 new colleagues: &lt;a href=&quot;https://twitter.com/t00cool&quot;&gt;David Lynam&lt;/a&gt;, Senior Cloud Architect, and &lt;a href=&quot;https://twitter.com/conzy_m&quot;&gt;Conor Maher&lt;/a&gt;, Senior Infrastructure Engineer and organiser of the &lt;a href=&quot;https://www.meetup.com/aws-user-group-south-east/&quot;&gt;AWS South East User Group in Ireland&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Our team spoke at over 30 conferences in 4 different continents, including AWS Cloud Day Dublin and the AWS AI &amp;#x26; Data Conference, where &lt;a href=&quot;https://twitter.com/eoins&quot;&gt;Eoin Shanaghy&lt;/a&gt; (our CTO) conducted a one-on-one interview with &lt;strong&gt;Werner Vogels&lt;/strong&gt;, CTO of Amazon.&lt;/li&gt;
&lt;li&gt;We celebrated two wins at the JSDAY Awards 2023: &lt;strong&gt;Best Place to Work with JavaScript in Ireland&lt;/strong&gt; and &lt;strong&gt;Most Valued JavaScript Open Source Project&lt;/strong&gt; for Middy.&lt;/li&gt;
&lt;li&gt;We proudly became an &lt;strong&gt;Amazon ECS Service Delivery Launch Partner&lt;/strong&gt;, validating our expertise in Amazon ECS and AWS Fargate.&lt;/li&gt;
&lt;li&gt;We open-sourced some new very cool projects such as &lt;a href=&quot;https://github.com/fourTheorem/podwhisperer&quot;&gt;&lt;code&gt;podwhisperer&lt;/code&gt; for automating podcast transcripts&lt;/a&gt; and &lt;a href=&quot;https://github.com/fourTheorem/episoder&quot;&gt;&lt;code&gt;episoder&lt;/code&gt; for automating chapters, tags, titles, and video descriptions from transcripts&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;We also kept investing in an open-source project we launched last year: &lt;a href=&quot;https://github.com/fourTheorem/slic-watch&quot;&gt;&lt;code&gt;slic-watch&lt;/code&gt; for automating observability on AWS&lt;/a&gt; which got mostly rewritten in TypeScript (thanks to all the efforts of our colleague &lt;a href=&quot;https://twitter.com/AkkocDiren&quot;&gt;Diren Akkoc&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What can we expect in the next year? Hard to say for sure, but I am sure it’s going to be exciting and rewarding!&lt;/p&gt;
&lt;p&gt;I am also happy to see that the company is growing and that we are always on the lookout for talent. If you like the cloud and you think you might be interested in joining us, reach out to me and/or check out the &lt;a href=&quot;https://fourtheorem.com/careers/&quot;&gt;fourTheorem careers page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, if you and your company are looking for help with AWS and the cloud, whether you are doing a cloud migration, an app modernization, building a scalable MVP for a startup idea or trying to optimize your cloud bill, &lt;a href=&quot;https://fourtheorem.com/contact-us/&quot;&gt;reach out to us&lt;/a&gt; and we’ll be more than happy to help!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It does not matter how slowly you go as long as you do not stop.&lt;/p&gt;
&lt;p&gt;— Confucius&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;public-speaking&quot;&gt;Public speaking&lt;/h2&gt;
&lt;p&gt;I am not sure if I can call myself a &lt;em&gt;public speaker&lt;/em&gt;, but I do enjoy speaking at conferences and meetups. I think it’s a great way to share knowledge and to meet new people. I also think it’s a great way to step out of your comfort zone, challenge yourself and grow as a person. If it’s something you haven’t done yet, I would recommend considering it.&lt;/p&gt;
&lt;p&gt;I have been doing public speaking since 2016 and in 2023 I reached a total of &lt;strong&gt;137 talks&lt;/strong&gt;! 🎉&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Luciano Mammino speaking at JSNation conference in Amsterdam&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;682&quot; src=&quot;https://loige.co/_astro/luciano-mammino-speaking-at-jsnation-amsterdam-2023-06-01.D3Z8kTmL_Z2bhag6.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;This is me delivering a talk about JavaScript iteration protocols at JSNation in Amsterdam. What an awesome experience!&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;One of my favourite speaking events was to deliver my first talk at a Rust conference (RustNation UK)! 🦀 This is really important for me because I feel I am still at the very beginning of my Rust journey and being able to speak in front of a crowd interested in Rust and possibly more knowledgeable than me was a great experience. I am looking forward to doing more of this in the future!&lt;/p&gt;
&lt;p&gt;The talk is called &lt;em&gt;“What I learned by solving 50 Advent of Code challenges in Rust”&lt;/em&gt;. It had a great reception and it’s available on YouTube with more than 12k views and tons of comments!&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://www.youtube.com/embed/udHjmno-tfA&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;&lt;small&gt;Spoiler, I’ll be presenting at RustNation UK again in 2024! 🎉&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;Here’s the full list of talks I delivered in 2023:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Interview with Caffé Sviluppo&lt;/em&gt; (Podcast interview in Italian, remote) (&lt;a href=&quot;https://www.youtube.com/watch?v=ggvowBqTtD8&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Building an invite-only microsite with Next.js &amp;#x26; Airtable&lt;/em&gt; (talk at Global Summit for Node.js, remote) (&lt;a href=&quot;https://loige.link/pizzapazza&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/live/seGVmqw2vTY?si=uh8cil7Zd0oa1crG&amp;#x26;t=3527&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;What I learned by solving 50 Advent of Code challenges in Rust&lt;/em&gt; (talk at Rust Nation, London) (&lt;a href=&quot;https://loige.link/crablearn&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=udHjmno-tfA&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Serverless su AWS&lt;/em&gt; (podcast interview with Gitbar podcast, remote, Italian) (&lt;a href=&quot;https://www.gitbar.it/episodes/ep147-serverless-su-aws-con-luciano-mammino-fourtheorem&quot;&gt;Episode&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Did you know JavaScript has iterators?&lt;/em&gt; (talk at DublinJS meetup, Dublin) (&lt;a href=&quot;https://loige.link/iterate&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;The evolution of Async JavaScript and its patterns&lt;/em&gt; (talk at Node.js ONE Africa conference, remote) (&lt;a href=&quot;https://loige.link/async-evo&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=DRxod84Ftws&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;AWS Application Composer e Amazon CodeCatalyst&lt;/em&gt; (talk at AWS User Group Roma, remote)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;A modern application is ASAP&lt;/em&gt; (talk at AWS Cloud Day, Dublin)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Your Lambdas, In Rust!&lt;/em&gt; (talk at Conf42: Cloud Native, remote) (&lt;a href=&quot;https://loige.link/rusty-lambdas&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://youtu.be/jJjdKJHqKkI&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Production-ready lambdas with Node.js&lt;/em&gt; (talk at JSDay Verona) (&lt;a href=&quot;https://loige.link/prod-lambda&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;A serverless architecture for high performance financial modelling&lt;/em&gt; (talk at Serverless Architecture Conference London) (&lt;a href=&quot;https://fth.link/sa23&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=9NyeoWqdIQk&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Your Lambdas, In Rust!&lt;/em&gt; (talk at AWS Fest remote) (&lt;a href=&quot;https://loige.link/lambda-rs&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=NwH2VZUnVU0&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;JavaScript Iteration Protocols&lt;/em&gt; (talk at JSNation Amsterdam) (&lt;a href=&quot;https://loige.link/iter-nation&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://portal.gitnation.org/contents/javascript-iteration-protocols&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;AWS On Air&lt;/em&gt; (interview at AWS Summit London) (&lt;a href=&quot;https://www.youtube.com/watch?v=Jc42iaSKaIc&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Production-ready lambdas with Node.js&lt;/em&gt; (talk at Sailsconf) (&lt;a href=&quot;https://loige.link/lambda-pirate&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=_OBBwuplpBY&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;The senior dev: an opinionated take&lt;/em&gt; (remote talk at Java Challenger) (&lt;a href=&quot;https://loige.link/senior&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/live/oO6zgqFuKCY?feature=share&amp;#x26;t=7061&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Easier Observability with SLIC Watch&lt;/em&gt; (remote talk at Serverless Office Hours) (&lt;a href=&quot;https://fth.link/observe&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=wexRZ_9Zfwk&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Rust, Serverless and AWS&lt;/em&gt; (talk at Rust Dublin) (&lt;a href=&quot;https://loige.link/oxidize-lambda&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=He4inXmMZZI&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Automating observability on AWS with SLIC Watch&lt;/em&gt; (talk at Ship It Conference Dublin) (&lt;a href=&quot;https://fth.link/auto-obs&quot;&gt;Slides&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Chats with “La locanda del tech”&lt;/em&gt; (remote panel - in Italian) (&lt;a href=&quot;https://www.youtube.com/watch?v=GHG3CxAWy6I&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Easier Observability with SLIC Watch&lt;/em&gt; (talk at ServerlessDays Belfast At Night) (&lt;a href=&quot;https://fth.link/sls-night&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=x8qpPpdsg1E&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Lambda in Rust&lt;/em&gt; (talk at AWS User Group Dublin) (&lt;a href=&quot;https://loige.link/lambda-rust&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Did you know JavaScript has iterators?&lt;/em&gt; (talk at JavaScript Global Summit) (&lt;a href=&quot;https://loige.link/iter-summit&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Everything I know about S3 pre-signed URLs&lt;/em&gt; (talk at AWS Community Summit Manchester) (&lt;a href=&quot;https://fth.link/sign-before&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=3sbz5y_WXTY&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Did you know JavaScript has iterators?&lt;/em&gt; (talk at Node.js Conference) (&lt;a href=&quot;https://loige.link/iter-garda&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Your Lambdas, In Rust!&lt;/em&gt; (talk at Codemotion Milan Milan) (&lt;a href=&quot;https://loige.link/lamb-rs&quot;&gt;Slides&lt;/a&gt;, &lt;a href=&quot;https://talks.codemotion.com/your-lambdas-in-rust&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Your Lambdas, In Rust!&lt;/em&gt; (talk at AWS User Group South East Waterford) (&lt;a href=&quot;https://fth.link/rust-lambda&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;AWS Serverless Hero at re:Invent&lt;/em&gt; (interview with vBrownBag) (&lt;a href=&quot;https://www.youtube.com/watch?v=ErJ8KpYd5B8&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Serverless Tips from an AWS Hero&lt;/em&gt; (online interview) (&lt;a href=&quot;https://www.youtube.com/watch?v=mfeF2aO8TTI&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What do you think? Is there any topic here that catches your attention? If so, let me know and I’ll be happy to work on more content around the same topic!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It usually takes me more than three weeks to prepare a good impromptu speech&lt;/p&gt;
&lt;p&gt;— Mark Twain&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;aws-bites&quot;&gt;AWS Bites&lt;/h2&gt;
&lt;p&gt;AWS Bites is a weekly podcast that Eoin Shanagy and I started in 2021. We are now in our third season and we are still growing steadily! 🎉&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Eoin and Luciano from AWS Bites standing behind a fake cutout representing our usual AWS Bites background frame. Luciano is doing the usual Italian pinch-hand gesture&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;757&quot; src=&quot;https://loige.co/_astro/eoin-and-luciano-from-aws-bites-in-a-fake-background-cutout.C3xUd7iM_hFRuA.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Here’s Eoin and I during the fourTheorem Christmas dinner. Our colleague Conor made for us this awesome cutout so that we can feel like real podcasters! I am doing the Italian &lt;em&gt;pinch gesture&lt;/em&gt;, because I am Italian, so I am entitled to it! 😅&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;This year we released &lt;strong&gt;46 episodes&lt;/strong&gt; which is almost one every week! It feels great to have been so consistent! We also surpassed the &lt;strong&gt;100-episode mark&lt;/strong&gt;! 🎉&lt;/p&gt;
&lt;p&gt;Let’s have a quick look at our YouTube numbers for 2023:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;YouTube stats for AWS Bites podcast in 2023&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2164&quot; height=&quot;1032&quot; src=&quot;https://loige.co/_astro/aws-bites-youtube-stats-2023.DqgXFZTZ_1qKHyE.webp&quot; &gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We more than &lt;strong&gt;doubled our number of views&lt;/strong&gt; from last year reaching &lt;strong&gt;~39k views&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;We also &lt;strong&gt;doubled the watch time&lt;/strong&gt; reaching &lt;strong&gt;3k hours of watch time&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;We have &lt;strong&gt;grown our subscriber base by ~40%&lt;/strong&gt; reaching &lt;strong&gt;~2.5 subscribers&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our followers seem to have enjoyed the following 3 episodes the most:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://awsbites.com/70-how-do-you-create-good-aws-diagrams/&quot;&gt;70. How do you create good AWS diagrams?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awsbites.com/57-cognito-user-pools-vs-identity-pools/&quot;&gt;57. Cognito User Pools vs. Identity Pools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awsbites.com/88-what-is-vpc-lattice/&quot;&gt;88. What is VPC Lattice?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now let’s compare these with some podcast numbers, based on what Spotify gives us:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;AWS Bites Spotify for Podcaster plays stats in 2023&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1200&quot; height=&quot;544&quot; src=&quot;https://loige.co/_astro/aws-bites-spotify-stats-2023.CesxO8bI_BNd8R.webp&quot; &gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We reached &lt;strong&gt;almost 60k plays&lt;/strong&gt; in 2023, which is almost &lt;strong&gt;double the number of plays&lt;/strong&gt; we had in 2022.&lt;/li&gt;
&lt;li&gt;We streamed in &lt;strong&gt;79 different countries&lt;/strong&gt; (with USA, UK, India, Canada and Germany being in our top 5).&lt;/li&gt;
&lt;li&gt;We have &lt;strong&gt;grown our follower base by 123%&lt;/strong&gt; reaching &lt;strong&gt;~2k Spotify followers&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The favourite episode was: &lt;a href=&quot;https://awsbites.com/60-what-is-aws-lambda/&quot;&gt;60. What is AWS Lambda?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The most shared episode was: &lt;a href=&quot;https://awsbites.com/83-bucket-list-of-s3-best-practices/&quot;&gt;83. Bucket List of S3 Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are curious to see more details you can check out &lt;a href=&quot;https://youtube.com/shorts/F6c_Ab8lwMk&quot;&gt;our Spotify for Podcasters wrapped 2023 YouTube short&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you enjoy AWS Bites, let us know what you think about it, what can we do to deliver more value to you, which topics you care about, etc. We are always looking for feedback and we are always happy to hear from our listeners on what we can do better!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you have knowledge, let others light their candles in it.&lt;/p&gt;
&lt;p&gt;— Margaret Fuller&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;live-coding-on-twitch&quot;&gt;Live coding on Twitch&lt;/h2&gt;
&lt;p&gt;In 2023 I continued my activity of &lt;a href=&quot;https://twitch.tv/loige&quot;&gt;live coding on Twitch&lt;/a&gt; together with my friend &lt;a href=&quot;https://twitter.com/gbinside&quot;&gt;Roberto Gambuzzi&lt;/a&gt;. I actually want to take the opportunity to give Roberto a big shout-out not just for the great company during these live coding streams (where he always brings a huge amount of expertise and some great fun too), but also for keeping me on track with streaming (more or less) regularly! So, yes, &lt;em&gt;Thanks Roberto!&lt;/em&gt; 🙏&lt;/p&gt;
&lt;p&gt;Let’s now share some stats:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Luciano Mammino&amp;amp;#x27;s Twitch streaming wrapped stats for 2023&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;1000&quot; src=&quot;https://loige.co/_astro/twitch-recap-loige-2023.BnOihEhA_ZptzGA.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Compared to last year we had &lt;strong&gt;fewer streams (30 vs 36)&lt;/strong&gt;, &lt;strong&gt;fewer new followers (150 vs 250)&lt;/strong&gt; and &lt;strong&gt;fewer hours watched (152 vs 223)&lt;/strong&gt;. A bit of a downward trend, but to be honest I am not too worried about it. We don’t stream because we have some kind of master plan to grow a huge community, but more as an excuse to keep learning about Rust and getting better as software engineers. In that sense, I think that the time spent doing this activity has been absolutely well spent!&lt;/p&gt;
&lt;p&gt;This year we focused much less on Advent of Code and we tried to invest more time learning about new interesting Rust crates and working on a few side projects. Here’s a summary of some of the most interesting streams (with a link to the respective recordings on YouTube):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Igajh2Vliog&quot;&gt;Learning &lt;code&gt;nom&lt;/code&gt;: Rust library to build parsers&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=lXiXdPmRqSk&quot;&gt;Learning &lt;code&gt;axum&lt;/code&gt;: Rust web framewrork&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=rqUH1Dnz8Ho&quot;&gt;Learning &lt;code&gt;dotenv&lt;/code&gt; &amp;#x26; &lt;code&gt;reqwest&lt;/code&gt; Rust libraries&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=mrOYFegU60U&quot;&gt;Learning &lt;code&gt;serde&lt;/code&gt;: Rust serialization and deserialization library&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=3Iezt-yUxd8&quot;&gt;Learning about Rust Async Iterators using &lt;code&gt;async_stream&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=YkTIGz_QAZM&quot;&gt;Learning the Rust crates &lt;code&gt;zip&lt;/code&gt; and &lt;code&gt;image&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=0FTEIBAzRyY&quot;&gt;Using &lt;code&gt;pyO3&lt;/code&gt;, a Rust library to create Python packages&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=yp9qdHYafOI&quot;&gt;Using Zig with Python&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=jkC4vik8__k&quot;&gt;Using &lt;code&gt;neon&lt;/code&gt;, a Rust library to create Node.js modules&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PLbNOKnE-Oyr1tsUft4j0QZDyk5iFcVVy_&quot;&gt;Various streams on how to re-design the automation around FullStack Bulletin&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PLbNOKnE-Oyr1I-Ddj4LX-VqDHj4qjTb49&quot;&gt;Various streams on building a Twitch chat integration in Rust&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;More Advent of Code in Rust (&lt;a href=&quot;https://www.youtube.com/watch?v=1mCrhSVQTGM&quot;&gt;Stream 1&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/watch?v=S7FwAUMt-kw&quot;&gt;Stream 2&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you think these kinds of topics are interesting, make sure to &lt;a href=&quot;https://twitch.tv/loige&quot;&gt;follow us on Twitch&lt;/a&gt; and &lt;a href=&quot;https://youtube.com/loige&quot;&gt;check out the recording on YouTube&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, a big shout-out to all the people who joined us during the streams and helped us with their comments and suggestions. We really appreciate it and we are looking forward to seeing you again in 2024! 🙏&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The people who interacted the most with Luciano and Roberto in their Twitch live streams in 2023&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;575&quot; src=&quot;https://loige.co/_astro/twitch-loudest-fans-loige-2023.SQOkFBt1_Z2gnSBg.webp&quot; &gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There’s progression you don’t see and feel.
There’s a starting point, and with time and focus.
As long as you reevaluate and reassess, and constantly objectively look at what you’re doing, and then pursue it with passion and focus, you get better at things.&lt;/p&gt;
&lt;p&gt;— Joe Rogan&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;nodejs-design-patterns&quot;&gt;Node.js Design Patterns&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://nodejsdesignpatterns.com/&quot;&gt;Node.js Design Patterns&lt;/a&gt; is a book I co-authored with the amazing &lt;a href=&quot;https://twitter.com/mariocasciaro&quot;&gt;Mario Casciaro&lt;/a&gt;. It is s still doing quite well even after 3.5 years since the third edition was published.&lt;/p&gt;
&lt;p&gt;The thing that is most rewarding about this book is that it keeps getting praised as one of the best resources to go from beginner to master with JavaScript and Node.js. I am really happy to see that the book is still relevant and that it’s helping people to learn and grow!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nodejsdp.link/buy&quot;&gt;&lt;img alt=&quot;Node.js Design Patterns reviews on Amazon.com: 4.7/5.0 with 279 reviews&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;993&quot; height=&quot;546&quot; src=&quot;https://loige.co/_astro/node-js-design-patterns-mario-casciaro-luciano-mammino-reviews-on-amazon.Bp_5-K_Z_Z2qJacV.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In 2023 we kept getting great reviews and we currently have &lt;strong&gt;4.7/5 stars on Amazon&lt;/strong&gt; (compared to 4.6 last year) and a total of 279 reviews (compared to 227 last year).&lt;/p&gt;
&lt;p&gt;Let me just quote &lt;a href=&quot;https://www.amazon.com/gp/customer-reviews/R26EIBOMYLHUMZ/ref=cm_cr_othr_d_rvw_ttl?ie=UTF8&amp;#x26;ASIN=1839214112&quot;&gt;a review from 2023&lt;/a&gt; that I particularly liked:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An excellent book, highly recommend it. Extremely useful, I read it 2 times and planning for the third one.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And here’s &lt;a href=&quot;https://www.goodreads.com/review/show/5727966468&quot;&gt;another one from GoodReads&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As a CS student who just wants to get into backend development with Node.js, all the time a hear terms like microservices, messaging, streams, containers, event loop, and caching, and I just get overwhelmed by the many terms I hear, until someone recommended this book to me, and it just guided me where everything falls in place, it’s not comprehensive it helps you explore and do small examples on how to do these stuff with Node.js. Trust me, it’s not just another “Design Patterns” book :)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;At the time of writing the book is also doing quite well in a few categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;#110,600 in the global Amazon ranking&lt;/strong&gt; (this one doesn’t mean much but it’s always a funny number to observe)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;#18 in JavaScript Programming&lt;/strong&gt; (compared to #22 last year)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;#23 in Web Services&lt;/strong&gt; (compared to #11 last year)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The book covers the most modern design patterns to make sure you write efficient and scalable Node.js and JavaScript code. It is also up to date to use modern language features such as ESM (EcmaScript modules), Async Iterators, and modern libraries and frameworks. The book targets Node.js 14 which is now deprecates, so, altough I believe the book is still very modern and relevant, it might be a good time to start thinking about a new edition. I am not sure if I can commit to it yet, but I’ll keep you posted if something happens!&lt;/p&gt;
&lt;p&gt;Meanwhile, if you have read the book, what do you think? Is there something missing? Something else you’d like to see in it? Let me know!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A book is a garden, an orchard, a storehouse, a party, a company by the way, a counselor, a multitude of counselors.&lt;/p&gt;
&lt;p&gt;— Charles Baudelaire&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;fullstack-bulletin&quot;&gt;FullStack Bulletin&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://fullstackbulletin.com/&quot;&gt;FullStack Bulletin&lt;/a&gt; is a free weekly newsletter about full-stack web development. I have been running this project with my dear friend &lt;a href=&quot;https://twitter.com/andreaman87&quot;&gt;Andrea Mangano&lt;/a&gt; for the last 6 years, now.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://us15.campaign-archive.com/?u=b015626aa6028495fe77c75ea&amp;#x26;id=d91a7c0643&quot;&gt;&lt;img alt=&quot;A screenshot of one of the latest issues of FullStack Bulletin - Issue #352 published on 2023-12-25&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1200&quot; height=&quot;852&quot; src=&quot;https://loige.co/_astro/fullstack-bulletin-screenshot-of-issue-352-2023-12-25.C0ASu7Bq_Z1cXclv.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;A screenshot of one of the latest issues of FullStack Bulletin - Issue #352 published on 2023-12-25&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;In 2023 we reached more than &lt;strong&gt;350 published issues&lt;/strong&gt; and a total of &lt;strong&gt;3000 subscribers&lt;/strong&gt; (compared to 2500 last year)! 🎉&lt;/p&gt;
&lt;p&gt;This year we invested a bit in improving our layout, adding more variety to our content, improving the &lt;a href=&quot;https://github.com/fullStackBulletin/automation&quot;&gt;automation&lt;/a&gt; around the newsletter, and, generally speaking, we tried to make the newsletter messaging more personal and direct.&lt;/p&gt;
&lt;p&gt;We are still running this project at a loss (Mailchimp is expensive! 💸), just for the sheer love of sharing full-stack content that we find interesting (and a bit selfishly as a tool to keep ourselves up to date with the news of the ever-evolving world of web development).&lt;/p&gt;
&lt;p&gt;If you are interested in full-stack web development, make sure to &lt;a href=&quot;https://fullstackbulletin.com/&quot;&gt;subscribe to FullStack Bulletin&lt;/a&gt; and let us know what you think about it!&lt;/p&gt;
&lt;p&gt;You can also support the project financially by sponsoring an issue! We can offer a sponsored banner, and a sponsored article slot. We can even discuss custom sponsorship packages. &lt;a href=&quot;mailto:luciano@fullstackbulletin.com&quot;&gt;Reach out to us&lt;/a&gt; if you are interested in knowing the details.&lt;/p&gt;
&lt;p&gt;A bit shout-out to our sponsors in 2023: &lt;strong&gt;MisterDA&lt;/strong&gt;, &lt;strong&gt;ConfigCat&lt;/strong&gt;, and &lt;strong&gt;Packt&lt;/strong&gt;. Thanks for supporting us! 🙏&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Curation is a natural and necessary extension of content creation. That is, as great as your content may be, your audience wants to learn from other experts and differing perspectives.&lt;/p&gt;
&lt;p&gt;— Pawan Deshpande&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;lifefoliage-the-landscape-hunt-game&quot;&gt;LifeFoliage: the Landscape Hunt game&lt;/h2&gt;
&lt;p&gt;In 2023, I was able to carve out some of my free time to support the &lt;a href=&quot;https://www.lifefoliage.eu/&quot;&gt;LifeFoliage&lt;/a&gt; project. LifeFoliage is a project funded by The Life Programme, the EU’s funding instrument for the environment and climate action. The project is very active in the Italian territory where it is focused on helping the local ecosystem to preserve and protect the local flora and fauna in a variety of ways.&lt;/p&gt;
&lt;p&gt;One of the things LifeFoliage does is monitor and raise awareness about the local flora and fauna. They do that by routinely performing remote sensing through satellite images, which is something that allows them to spot changes in the vegetation and to identify things like fires or deforestation activities.&lt;/p&gt;
&lt;p&gt;In this context, they wanted to create a publicly available game that could capture the essence of their work. This is how &lt;a href=&quot;https://game.lifefoliage.eu/&quot;&gt;Landscape Hunt&lt;/a&gt; was born.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A screenshot of a game session of LandScape Hunt&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;895&quot; src=&quot;https://loige.co/_astro/a-screenshot-of-a-game-session-of-landscape-hunt.CavKjXm7_Z1Yl32B.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;A screenshot of a game session of LandScape Hunt&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;Landscape Hunt is a game where you are presented with a series of satellite images and you have to spot guess what’s the right classification for that image. Are you looking at a fire, a forest cutting, a deciduous forest, a quarry or something else? It’s not that easy to guess correctly if you are not trained, so the game can be quite fun to play.&lt;/p&gt;
&lt;p&gt;From a technical perspective, this was my first production Rust project, in fact, it features a Rust backend (written with &lt;a href=&quot;https://github.com/tokio-rs/axum&quot;&gt;Axum&lt;/a&gt;) while the frontend is written using &lt;a href=&quot;https://www.solidjs.com/&quot;&gt;SolidJS&lt;/a&gt; and TypeScript.&lt;/p&gt;
&lt;p&gt;A big thanks to the team responsible for LifeFoliage and Landscape Hunt for involving me in this awesome project.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The greatest threat to our planet is the belief that someone else will save it.&lt;/p&gt;
&lt;p&gt;— Robert Swan&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;articles--blog&quot;&gt;Articles &amp;#x26; blog&lt;/h2&gt;
&lt;p&gt;In 2023 I kept writing articles occasionally on this blog and on other platforms. Here’s the full list of all the articles published in 2023 in this blog:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/the-senior-dev&quot;&gt;The Definition of Senior: A Look at the expectations for Software Engineers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/building_x86_rust-containers-from-mac-silicon&quot;&gt;Building x86 Rust containers from Mac Silicon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/why-you-should-consider-rust-for-your-lambdas&quot;&gt;Why you should consider Rust for your Lambdas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/debugging-custom-apigateway-authorizers&quot;&gt;Debugging custom ApiGateway authorizers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/javascript-low-level-or-ai&quot;&gt;JavaScript, low-level or AI?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also wrote a few articles for other platforms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://fourtheorem.com/the-illustrated-guide-to-s3-pre-signed-urls/&quot;&gt;The illustrated guide to S3 pre-signed URLs&lt;/a&gt; (published on fourTheorem blog)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://awscq.substack.com/p/the-case-for-serverless-rust-on-aws&quot;&gt;The case for Serverless Rust on AWS&lt;/a&gt; (published in the AWS Comsum Quarterly Newsletter)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.codemotion.com/magazine/it/carriere-tech/la-definizione-di-sviluppatore-senior/&quot;&gt;La definizione di Sviluppatore Senior (ita)&lt;/a&gt; (published on Codemotion’s blog as a liberal translation of my article “The definition of Senior”, kindly translated by Mauro Bardetta).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I was going to publish some stats about the blog, but the migration to Google Analytics V4 has messed up all my historic data and I am left with only &lt;strong&gt;~18K user sessions from July 2023&lt;/strong&gt;! Sigh. 😭&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Google Analytics v4 data for loige.co also showing missing historic data due to the migration to v4&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;534&quot; src=&quot;https://loige.co/_astro/google-analytics-v4-is-great-for-losing-historic-data.CtS1OyBU_Z2irFbG.webp&quot; &gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Blogging is to writing what extreme sports are to athletics: more free-form, more accident-prone, less formal, more alive. It is, in many ways, writing out loud.&lt;/p&gt;
&lt;p&gt;— Andrew Sullivan&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;open-source&quot;&gt;Open Source&lt;/h2&gt;
&lt;p&gt;I always like to do some open source whenever I have the chance. I like to contribute to projects I use (even in small ways) and I like to share almost everything I do in an open-source fashion. No surprise that I kept my commit race going in 2023! 🎉&lt;/p&gt;
&lt;p&gt;Here’s a list of my most meaningful contributions of 2023:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Various contributions to &lt;a href=&quot;https://github.com/lmammino/jwt-cracker&quot;&gt;&lt;code&gt;lmammino/jwt-cracker&lt;/code&gt;&lt;/a&gt; (mostly merging PRs and general cleanups and improvements). Also, this is the first project where I introduced &lt;a href=&quot;https://biomejs.dev/&quot;&gt;Biome&lt;/a&gt; a new Rust-powered JavaScript/TypeScript formatter and linter which is quite promising!&lt;/li&gt;
&lt;li&gt;Continued working on some Advent of Code challenges in Rust (mostly during December 2023). All my solutions are in &lt;a href=&quot;https://github.com/lmammino/rust-advent&quot;&gt;&lt;code&gt;lmammino/rust-advent&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/lexicoid&quot;&gt;&lt;code&gt;lmammino/lexicoid&lt;/code&gt;&lt;/a&gt;: a simple Rust crate implementing short &amp;#x26; stable IDs based on timestamps. Based on a Go library (&lt;a href=&quot;https://github.com/brandur/sorg&quot;&gt;&lt;code&gt;brandur/sorg&lt;/code&gt;&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/eslint-community/eslint-plugin-security/&quot;&gt;&lt;code&gt;eslint-community/eslint-plugin-security&lt;/code&gt;&lt;/a&gt; &lt;a href=&quot;https://github.com/eslint-community/eslint-plugin-security/pull/95&quot;&gt;my PR&lt;/a&gt; co-authored together with &lt;a href=&quot;https://github.com/simone-sanfratello&quot;&gt;Simone Sanfratello&lt;/a&gt; was merged making ESLint able to spot some possible security issues in copy-pasted code.&lt;/li&gt;
&lt;li&gt;Some small contributions to an &lt;a href=&quot;https://github.com/codurance/rust-nation-intermediate-workshop&quot;&gt;awesome Rust workshop by @jfacchini&lt;/a&gt; that I had the fortune to partecipate to during Rust Nation UK 2023.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/lastfm&quot;&gt;&lt;code&gt;lmammino/lastfm&lt;/code&gt;&lt;/a&gt;: An async Rust client to fetch your Last.fm listening history or the track you are currently playing.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/image-overlay-example&quot;&gt;&lt;code&gt;lmammino/image-overlay-example&lt;/code&gt;&lt;/a&gt;: A very simple rust script showcasing how to create an image by overlaying two existing images.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/unzip-and-resize-images&quot;&gt;&lt;code&gt;lmammino/unzip-and-resize-images&lt;/code&gt;&lt;/a&gt;: A simple rust-based CLI that can read images from a zip file, resize them and save the resulting images in a local folder.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/aws-application-composer-demo&quot;&gt;&lt;code&gt;lmammino/aws-application-composer-demo&lt;/code&gt;&lt;/a&gt;: An AWS Application Composer project created during a LIVE demo at the AWS User Group Roma.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/earthquake-notifier&quot;&gt;&lt;code&gt;lmammino/earthquake-notifier&lt;/code&gt;&lt;/a&gt;: Lambda in Rust to monitor for earthquakes and generate EventBridge events.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/mvp-contributions&quot;&gt;&lt;code&gt;lmammino/mvp-contributions&lt;/code&gt;&lt;/a&gt;: a CLI tool to review and submit your Microsoft MVP contributions using a YAML file. I was very proud of this one because it saved me so much time when I had to submit my MVP contributions. For better or worse, Microsoft has recently updated the MVP program website and this tool no longer works. I’ll need to find some time to update it to use the new APIs.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/solidjs-template&quot;&gt;&lt;code&gt;lmammino/solidjs-template&lt;/code&gt;&lt;/a&gt;: A dead simple Solid.js starter template (using npm, ESLint, StandardJS, and TypeScript).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/zig-python-experiment&quot;&gt;&lt;code&gt;lmammino/zig-python-experiment&lt;/code&gt;&lt;/a&gt;: A simple Python module written in Zig (mostly work done by &lt;a href=&quot;https://twitter.com/gbinside&quot;&gt;Roberto Gambuzzi&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Fixed a small typo in &lt;a href=&quot;https://github.com/rafaelcaricio/backie/pull/3/files&quot;&gt;&lt;code&gt;rafaelcaricio/backie&lt;/code&gt;&lt;/a&gt;, a library to do background task processing for Rust applications with Tokio, Diesel, and PostgreSQL.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/pyo3-experiment&quot;&gt;&lt;code&gt;lmammino/pyo3-experiment&lt;/code&gt;&lt;/a&gt;: an example project where we used PyO3 to run Rust code from a Python module.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/http-check&quot;&gt;&lt;code&gt;lmammino/http-check&lt;/code&gt;&lt;/a&gt;: A dead-simple Lambda to demonstrate some best practices for Node.js Lambdas like logging, custom metrics, testing, etc.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/playing-with-neon&quot;&gt;&lt;code&gt;lmammino/playing-with-neon&lt;/code&gt;&lt;/a&gt;: Some simple experiment with Neon bindings: generating Node.js libraries with Rust&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/js-iter-examples&quot;&gt;&lt;code&gt;lmammino/js-iter-examples&lt;/code&gt;&lt;/a&gt;: Code examples from my talk “JavaScript iteration protocols”&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FullStackBulletin/tech-quotes&quot;&gt;&lt;code&gt;FullStackBulletin/tech-quotes&lt;/code&gt;&lt;/a&gt;: An API to get interesting tech-related quotes (powered by GitHub pages).&lt;/li&gt;
&lt;li&gt;Various improvements to &lt;a href=&quot;https://github.com/lmammino/jwtinfo&quot;&gt;&lt;code&gt;lmammino/jwtinfo&lt;/code&gt;&lt;/a&gt;: A command-line tool (written in Rust) to get information about JWTs (Json Web Tokens).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/tapo-l920-on-off&quot;&gt;&lt;code&gt;lmammino/tapo-l920-on-off&lt;/code&gt;&lt;/a&gt;: A very simple Rust binary that can turn on/off a TP-Link L920 led light strip in your local network.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/twitch-chat-bot&quot;&gt;&lt;code&gt;lmammino/twitch-chat-bot&lt;/code&gt;&lt;/a&gt;: An (incomplete and experimental) Twitch Chat bot written in Rust.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Il-Libro-Open-Source/book/pull/182&quot;&gt;Contribution&lt;/a&gt; to &lt;a href=&quot;https://github.com/Il-Libro-Open-Source/book&quot;&gt;Il-Libro-Open-Source/book&lt;/a&gt;: an Italian open-source project that aims to become an open book about best practices and suggestions on how to become a good software developer. I contributed by writing an entire chapter about the skills that are needed to be considered a great Senior software developer.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/oidc-authorizer&quot;&gt;&lt;code&gt;lmammino/oidc-authorizer&lt;/code&gt;&lt;/a&gt;: A high-performance Lambda authorizer for API Gateway that can validate OIDC tokens (written in Rust).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/aws-samples/serverless-patterns/pull/1910&quot;&gt;Small contribution&lt;/a&gt; to &lt;a href=&quot;https://github.com/aws-samples/serverless-patterns&quot;&gt;&lt;code&gt;aws-samples/serverless-patterns&lt;/code&gt;&lt;/a&gt; making Node.js imports consistent.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/whisper-rs-example&quot;&gt;&lt;code&gt;lmammino/whisper-rs-example&lt;/code&gt;&lt;/a&gt;: An example of how to use Whisper.cpp bindings for Rust to perform speech-to-text on WAV audio files.&lt;/li&gt;
&lt;li&gt;A &lt;a href=&quot;https://github.com/aws/aws-cdk/pull/28414&quot;&gt;minor contribution&lt;/a&gt; &lt;a href=&quot;https://github.com/aws/aws-cdk&quot;&gt;&lt;code&gt;aws/aws-cdk&lt;/code&gt;&lt;/a&gt; making sure that a specific edge case would provide good logging. I had quite some fun working on this one together with my colleague &lt;a href=&quot;https://twitter.com/conzy_m&quot;&gt;Conor Maher&lt;/a&gt; and I am very proud of this contribution since we use CDK quite a lot at fourTheorem.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To close this section here’s my ritual GitHub yearly contribution graph! I know it’s just vanity, but it’s fun! 😀&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;GitHub contribution chart of Luciano Mammino (lmammino) in 2023&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;310&quot; src=&quot;https://loige.co/_astro/lmammino-github-contribution-chart-2023.CNA_gT4l_Z1OuANJ.webp&quot; &gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I often compare open source to science. Science took this whole notion of developing ideas in the open and improving on other peoples’ ideas. It made science what it is today and made the incredible advances that we have had possible. And I compare that to witchcraft and alchemy, where openness was something you didn’t do.&lt;/p&gt;
&lt;p&gt;— Linus Torvalds&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;other-stuff&quot;&gt;Other stuff&lt;/h2&gt;
&lt;p&gt;Some other quick professional news (even though they are not really news).&lt;/p&gt;
&lt;h3 id=&quot;still-an-mvp&quot;&gt;Still an MVP&lt;/h3&gt;
&lt;p&gt;In 2023 I was &lt;strong&gt;confirmed as a Microsoft Most Valuable Professional for Developer Technologies and Security&lt;/strong&gt;. This marks &lt;a href=&quot;https://mvp.microsoft.com/it-IT/mvp/profile/e25db9eb-f3bd-eb11-bacc-0022481f2c24&quot;&gt;3 years as an MVP&lt;/a&gt;! 🎉&lt;/p&gt;
&lt;p&gt;Unfortunately, I cannot show you the &lt;a href=&quot;/2022-a-year-in-review/#confirmed-as-mvp&quot;&gt;usual MVP tower trophy where I am adding another disc&lt;/a&gt; because my parcel got lost in transit and I haven’t been able to schedule another shipping with Microsoft 😢. BTW, if you work with Microsoft (or you know someone who can help), please let me know. I have sent countless emails and Teams messages already but it seems they are not reaching the right people… 🙁&lt;/p&gt;
&lt;h3 id=&quot;still-a-codemotion-ambdassador&quot;&gt;Still a Codemotion Ambdassador&lt;/h3&gt;
&lt;p&gt;In 2022 I became a Codemotion Ambassador.&lt;/p&gt;
&lt;p&gt;Codemotion is the biggest tech conference (and tech community) in Italy and one of the biggest in Europe. I have been speaking at Codemotion conferences for many years now and I have always been a big fan of their events. I am very happy to be part of the Codemotion Ambassador team and even more to still be part of this group in 2023!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Part of the Codemotion Ambassador team at Codemotion Milan 2023&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;576&quot; src=&quot;https://loige.co/_astro/part-of-the-codemotion-ambassador-team-at-codemotion-milan-2023.DbIzlP8s_Z160ku9.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;In this picture some members of Codemotion and the Codemotion Ambassador team during the after-party at Codemotion Milan 2023. From left to Right: &lt;a href=&quot;https://twitter.com/BertainaMichela&quot;&gt;Michela Bertaina&lt;/a&gt;, &lt;em&gt;a random guy&lt;/em&gt;, &lt;a href=&quot;https://www.linkedin.com/in/raibaz/&quot;&gt;Mattia Tommasone&lt;/a&gt; &lt;em&gt;a.k.a. “Mr. DJ”&lt;/em&gt;,  &lt;a href=&quot;https://twitter.com/GSantomaggio&quot;&gt;Gabriele Santomaggio&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/FrancescoSciuti&quot;&gt;Francesco Sciuti&lt;/a&gt; &lt;em&gt;a.k.a. “Batman”&lt;/em&gt;, &lt;a href=&quot;https://twitter.com/kasuken&quot;&gt;Emanuele Bartolesi&lt;/a&gt; &lt;em&gt;a.k.a “The Machine”&lt;/em&gt;, &lt;a href=&quot;https://twitter.com/cesalberca&quot;&gt;César Alberca&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/Maraexceptioon&quot;&gt;Mara Marzocchi&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;Thanks for having me in this awesome community! I look forward to contributing more to it in 2024!&lt;/p&gt;
&lt;p&gt;… Also, a tiny extra thank you to Emanuele Bartolesi for reminding me to write this post! 😝&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The future of every community lies in capturing the passion, imagination, and resources of its people.&lt;/p&gt;
&lt;p&gt;— Ernesto Sirolli&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;some-random-personal-stuff&quot;&gt;Some random personal stuff&lt;/h2&gt;
&lt;p&gt;Now, onto some other more personal achievements of 2023 🦸🏻&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;After 2 years pandemic hiatus from Brazilian Jiu Jitsu (BJJ), this year I finally restarted my training and towards the end of the year, I received the grade of &lt;strong&gt;purple belt&lt;/strong&gt;! 🥋&lt;/li&gt;
&lt;li&gt;I took a wonderful road trip &lt;strong&gt;visiting some of the most iconic national parks in California, Arizona, Utah and Nevada&lt;/strong&gt; with my wife and it was probably the best trip I (and we) ever had so far! ❤️&lt;/li&gt;
&lt;li&gt;Kept &lt;strong&gt;running&lt;/strong&gt; (even though less regularly than I did in the last 2 years) totaling &lt;strong&gt;~160Km in 27 runs&lt;/strong&gt;. 🏃&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;The horseshoe bend&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;768&quot; height=&quot;1024&quot; src=&quot;https://loige.co/_astro/the-horseshoe-bend.C7Bhs3_5_Z18KXnK.webp&quot; &gt;
&lt;small&gt;One of my pictures from a visit to the Horseshoe Bend, a horseshoe-shaped incised meander of the Colorado River located near the town of Page, Arizona, United States&lt;/small&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Enjoy the little things in life, for one day you may look back and realize they were the big things.&lt;/p&gt;
&lt;p&gt;— Robert Breault&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;That’s all folks!&lt;/p&gt;
&lt;p&gt;I am impressed to see that you got this far. Maybe it wasn’t as boring as I had imagined 😇&lt;/p&gt;
&lt;p&gt;It’s great to reflect on everything that happened in 2023 and start to think about what to invest my time and energies in 2024. I am not sure what the future holds, but I am sure it will be fun and exciting!&lt;/p&gt;
&lt;p&gt;What about you? What did you achieve in 2023 (or missed)? What’s your masterplan (if any) for 2024? I hope I’ll be reading about it in your own year in review post or in the comments below! 😉&lt;/p&gt;
&lt;p&gt;Bye 👋&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/2023-a-year-in-review.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/2023-a-year-in-review.png" width="1200" height="630"/></media:content><category>life</category><author>Luciano Mammino</author><comments>https://loige.co/2023-a-year-in-review/#comments</comments><enclosure url="https://loige.co/og/2023-a-year-in-review.png" length="0" type="image/png"/></item><item><title>2024 - A year in Review</title><link>https://loige.co/2024-a-year-in-review/</link><guid isPermaLink="true">https://loige.co/2024-a-year-in-review/</guid><description>In his 2024 year-in-review, Luciano Mammino covers his work in Rust, serverless AWS projects, his contributions to open source projects like Middy, public speaking engagements, the AWS Bites podcast, and personal milestones.</description><pubDate>Sun, 09 Feb 2025 20:12:00 GMT</pubDate><content:encoded>&lt;p&gt;2024: Another Year Bites the Dust (in a Good Way!)&lt;/p&gt;
&lt;p&gt;Another year has come and gone, leaving behind a trail of commits, conferences,
and hopefully, fewer bugs than it introduced! 🐞 I have been meaning to write
this review for the last 2 months, but it has been an intense last 2 months,
both personally and professionally! Finally, I am finding some time today, so I
am going to use it &lt;em&gt;wisely&lt;/em&gt; to do this boring task! Yes, the boring task is my
annual review of the things I’ve managed to accomplish (or at least attempt) in
2024, both professionally and personally.&lt;/p&gt;
&lt;p&gt;As usual, a disclaimer: this post is primarily for my own record-keeping and
reflection. I don’t expect anyone to actually &lt;em&gt;read&lt;/em&gt; it, but if you do, I hope
you’re comfortable, have a beverage of choice, and find it mildly entertaining
enough to not induce instant sleep. Think of it as a digital lullaby for the
tech-minded.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Spongebob saying &amp;quot;Nobody Cares&amp;quot; while drawing a rainbow in the air with their hands&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;200&quot; height=&quot;150&quot; src=&quot;https://loige.co/_astro/spongebob-nobody-cares.5c0vngqk_1hv5pT.webp&quot; &gt;&lt;/p&gt;
&lt;h2 id=&quot;launching-crafting-lambda-functions-in-rust-e-book&quot;&gt;Launching “Crafting Lambda Functions in Rust” (e-book)&lt;/h2&gt;
&lt;p&gt;Okay, the title might be a tad misleading! This isn’t a proper launch in the
traditional sense, since the book is very much still a work in progress. But
it’s also not entirely inaccurate, because the book is already available online,
and you can start reading it right now. If you want to dive even deeper into how
this book came to be,
&lt;a href=&quot;/coauthoring-a-book-about-rust-and-lambda/&quot;&gt;I wrote a dedicated article about it on this blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But let me tell you the story (or at least a condensed version)…&lt;/p&gt;
&lt;p&gt;Back in March 2024, I bumped into the amazing James Eastham, again! This time it
was at Rust Nation in London. I’ve been following James’s work for a while now,
because I love his content and because we both share a keen interest in
exploring the world of Rust, especially when applied to serverless
architectures.&lt;/p&gt;
&lt;p&gt;As we were chatting at the conference, it became apparent that we were both
individually thinking about creating a more structured resource around this
topic. After comparing notes, we decided to join forces and build something
together! If you’re as passionate about serverless and Rust as we are, you’ll
want to check this out!&lt;/p&gt;
&lt;p&gt;It didn’t take long for us to decide to go with a self-published book. We
started drafting ideas for chapters and shaping the overall messaging of the
book. We picked a title, designed &lt;a href=&quot;https://rust-lambda.com&quot;&gt;a website&lt;/a&gt;, created
a &lt;a href=&quot;https://loige.gumroad.com/l/rust-lambda&quot;&gt;store page on Gumroad&lt;/a&gt;, and even
created a mascot, which you can appreciate in all its full glory on our book
cover. I’m sure you can spot the various bits of inspiration we drew from! Yes,
our mascot is a crab (a cRustacean, get it?) with a Lambda hat. If the hat
reminds you of &lt;em&gt;something&lt;/em&gt; that’s a total coincidence… &lt;em&gt;Mamma mia&lt;/em&gt;!&lt;/p&gt;
&lt;div style=&quot;text-align:center; display: block; max-width: 400px; margin: 0 auto;&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://rust-lambda.com&quot;&gt;&lt;img alt=&quot;The cover of the book Crafting Lambda Functions in Rust&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;800&quot; height=&quot;1131&quot; src=&quot;https://loige.co/_astro/crafting-lambda-functions-in-rust-cover-light.BXtQJVpi_Z1hwGeb.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Now, let’s talk a bit about the publishing model we’ve chosen. We could have
tried to find a traditional publisher, but our previous experiences tell us that
this isn’t generally a viable way to make a project economically sustainable
(except for the publisher, of course… 🤫). Plus, we wanted total freedom over
the release schedule and how we interact with readers, offer discounts, and so
on. That’s why we decided to go the self-publishing route. This gives us full
control over how we interact with the community!&lt;/p&gt;
&lt;p&gt;Also, in order to keep ourselves committed and to have a steady stream of
feedback and reviews, we decided to make the book available as soon as we had
the draft of the first two chapters ready. We’re embracing the “early access”
approach!&lt;/p&gt;
&lt;p&gt;So you might be asking yourself… Why Rust and Lambda? Well, the combination of
Rust and AWS Lambda is a game changer. As a compiled language, Rust produces
highly efficient binaries that are compact and lightning-fast. This means your
Lambda functions run quicker, consume less memory, and ultimately cost less to
execute. You can potentially lower both execution cost and resource usage,
leading to a lower carbon footprint. You also get reliability and correctness as
Rust’s strict compiler and type system are like having an extra pair of eyes on
your code. Combine that with &lt;a href=&quot;https://www.cargo-lambda.info/&quot;&gt;Cargo Lambda&lt;/a&gt;, a
fantastic tool that streamlines the developer experience by handling
scaffolding, testing, compilation, and deployment, and you have an incredible
tool chain!&lt;/p&gt;
&lt;p&gt;As of today, we have six chapters available covering everything you need to know
to build and ship a fully functional URL shortener to AWS using Rust, Lambda,
and other serverless technologies (e.g., DynamoDB, API Gateway). In those 6
chapters you will learn everything from setting up your environment, creating
your first “Hello World” lambda and using SAM to manage your code, to testing
the lambda and making it interact with external systems.&lt;/p&gt;
&lt;p&gt;There’s still plenty of work to be done, but we plan to finish (or get close to
finishing) this book by the end of 2025. This book is your hands-on guide to
building efficient, scalable, and cost-effective serverless applications with
AWS Lambda functions and using the power of the Rust programming language. You
can even get involved by sharing your feedback, help shape the final version,
and, if you like, get your name on the book by purchasing the currently
available early release bundle!&lt;/p&gt;
&lt;p&gt;If you want to find out more, &lt;a href=&quot;https://rust-lambda.com/&quot;&gt;check out our website&lt;/a&gt;,
and if you want to stay up-to-date with the project, we also have
&lt;a href=&quot;https://news.rust-lambda.com/&quot;&gt;a newsletter&lt;/a&gt; and
&lt;a href=&quot;https://discord.gg/jXF5VSHMDW&quot;&gt;a Discord server&lt;/a&gt;. We’re excited to build
something amazing with you!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Reading maketh a full man; conference a ready man; and writing an exact man.&lt;br&gt;
— Francis Bacon&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;almost-4-years-of-cloud-adventures-at-fourtheorem&quot;&gt;Almost 4 Years of Cloud Adventures at fourTheorem&lt;/h2&gt;
&lt;p&gt;It’s almost been four years since I joined
&lt;a href=&quot;https://fourtheorem.com/&quot;&gt;fourTheorem&lt;/a&gt; as a Senior Cloud Architect! In fact, as
I’m writing this, that “almost” is just a week away! 🎉 They say time flies when
you’re having fun, and I can certainly say that time has been flying for me when
I think back on all we’ve accomplished at fourTheorem in these four years.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A fourTheorem sticker on a yellow background&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;639&quot; src=&quot;https://loige.co/_astro/fourtheorem-sticker.DRCXaBSf_Z1HBcm3.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;In 2024, I was fortunate enough to help several more enterprises achieve success
with AWS and Serverless, and I learned a ton in the process. I’m currently
working on a full-stack serverless project that has been incredibly rewarding to
build. It’s led me to explore a lot of new things around
&lt;a href=&quot;/tag/serverless&quot;&gt;serverless&lt;/a&gt; architectures, &lt;a href=&quot;/tag/typescript&quot;&gt;TypeScript&lt;/a&gt;,
OpenAPI, and more. I’m hoping to be able to share some of these learnings in a
public form soon! Stay tuned for that.&lt;/p&gt;
&lt;p&gt;From a company perspective, fourTheorem is growing strong. So, if you’re
passionate about the cloud and looking for a challenging and rewarding career,
check out the &lt;a href=&quot;https://fourtheorem.com/careers/&quot;&gt;fourTheorem careers page&lt;/a&gt; or
reach out to me directly. We’re always looking for talented individuals to join
our team. Come join the fun!&lt;/p&gt;
&lt;p&gt;2025 is already looking quite busy and I look forward to seeing what we will be
building with our clients and the team at fourTheorem!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Try to be a rainbow in someone’s cloud.&lt;br&gt;
— Maya Angelou&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;public-speaking-sharing-learning-and-connecting-at-conferences&quot;&gt;Public Speaking: Sharing, Learning, and Connecting at Conferences&lt;/h2&gt;
&lt;p&gt;This year, I’ve really enjoyed attending various conferences and delivering
talks. It’s one of the things I love most about my job. It doesn’t just give me
the opportunity to share what I’ve learned; more importantly, it gives me the
chance to meet likeminded people and learn from them. Building a network of
passionate software engineers is one of the most precious assets you can have in
this line of business.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Some of the conference badges that I collected in 2024&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;640&quot; src=&quot;https://loige.co/_astro/conference-badges-2024.Dw9w5OGs_2pC3so.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;So, I would encourage everyone to attend conferences. You don’t necessarily have
to try to deliver a talk if that’s not your thing, but attending should be an
absolute no-brainer! If you can take one thing away from this (admittedly
selfish) article, it’s to plan a few conferences to attend this year. And if you
think conferences are too expensive or too much of a commitment, you can always
start with a local meetup… Thank me later! 😉&lt;/p&gt;
&lt;p&gt;Here’s a look back at the talks I delivered in 2024:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;01-23: &lt;strong&gt;Re:Invent recap (panel)&lt;/strong&gt;, BelfAWSt User Group, Belfast&lt;/li&gt;
&lt;li&gt;01-30: &lt;strong&gt;AWS re:Invent re:Cap (panel)&lt;/strong&gt;, AWS User Group Dublin&lt;/li&gt;
&lt;li&gt;03-06: &lt;strong&gt;An intro to nom, parsing made easy for Rustaceans&lt;/strong&gt;, Rust Dublin
(Remote) (&lt;a href=&quot;https://loige.link/nom-rs&quot;&gt;Slides&lt;/a&gt;,
&lt;a href=&quot;https://www.youtube.com/live/1atZzA3e3Kg?t=972&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;03-19: &lt;strong&gt;Serverless Rust su AWS Lambda “for fun and profit” (Workshop)&lt;/strong&gt;,
Codemotion Workshop Fest (Remote) (&lt;a href=&quot;https://loige.link/cm2024-rust&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;03-28: &lt;strong&gt;Rust, Serverless, and AWS - Writing Lambdas in Rust&lt;/strong&gt;, Rust Nation
UK, London (&lt;a href=&quot;https://loige.link/lambda-nation-24&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;05-07: &lt;strong&gt;Your Lambdas, In Rust!&lt;/strong&gt;, AWS Community Nordics, Copenhagen
(&lt;a href=&quot;https://loige.link/l-rs&quot;&gt;Slides&lt;/a&gt;,
&lt;a href=&quot;https://www.youtube.com/watch?v=npqrTU2vK9c&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;05-23: &lt;strong&gt;Building Secure and Efficient SaaS Platforms on AWS Serverless&lt;/strong&gt;,
ServerlessDays Belfast (&lt;a href=&quot;https://fth.link/tenants&quot;&gt;Slides&lt;/a&gt;,
&lt;a href=&quot;https://www.youtube.com/watch?v=JB7d0427HLE&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;06-20: &lt;strong&gt;Rust on AWS Lambda&lt;/strong&gt;, Rustship podcast (Remote)
(&lt;a href=&quot;https://www.youtube.com/live/Qx0XIP4LnYU&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;08-14: &lt;strong&gt;Rust with Lambda, easy-mode Rust &amp;#x26; future of Middy&lt;/strong&gt;, Real World
Serverless podcast (Remote)
(&lt;a href=&quot;https://www.youtube.com/watch?v=FVYub3dzrAY&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;08-20: &lt;strong&gt;Harder, better, faster, stronger Lambda functions with Rust&lt;/strong&gt;,
Believe In Serverless (Remote) (&lt;a href=&quot;https://loige.link/hbfs&quot;&gt;Slides&lt;/a&gt;,
&lt;a href=&quot;https://www.youtube.com/watch?v=eqUehphXNvs&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;09-06: &lt;strong&gt;Faster/Greener/Cheaper Serverless compute with Lambda &amp;#x26; Rust&lt;/strong&gt;, AWS
Community Day Belfast (&lt;a href=&quot;https://loige.link/be-a-crab&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;09-16: &lt;strong&gt;Rust and Serverless Computing&lt;/strong&gt;, Mainmatter podcast (Remote)
(&lt;a href=&quot;https://www.youtube.com/watch?v=U9JZD7d9OmA&quot;&gt;Video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;09-17: &lt;strong&gt;Building Secure and Efficient SaaS Platforms on AWS Serverless&lt;/strong&gt;, AWS
Community Day DACH (&lt;a href=&quot;https://fth.link/aws-saas&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;09-27: &lt;strong&gt;Managing AWS accounts like a PRO&lt;/strong&gt;, AWS Community Day Italy, Rome
(&lt;a href=&quot;https://loige.link/accounts&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;10-03: &lt;strong&gt;Building Secure and Efficient SaaS Platforms on AWS Serverless&lt;/strong&gt;, AWS
Community Day NL (&lt;a href=&quot;https://fth.link/saas-nl&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;10-22: &lt;strong&gt;Building Secure and Efficient SaaS Platforms on AWS Serverless&lt;/strong&gt;,
Codemotion Milan (&lt;a href=&quot;https://fth.link/saas-mi&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;10-23: &lt;strong&gt;Unleashing Serverless Performance: Writing Optimized AWS Lambda
Functions with Rust (Workshop)&lt;/strong&gt;, Codemotion Milan
(&lt;a href=&quot;https://loige.link/rusty-sls&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;11-26: &lt;strong&gt;Faster/Greener/Cheaper Serverless compute with Lambda &amp;#x26; Rust&lt;/strong&gt;, Porto
Tech Hub (&lt;a href=&quot;https://loige.link/sls-w-rust&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;12-12: &lt;strong&gt;Optimized Lambda functions with Rust (Workshop)&lt;/strong&gt;, Serverless Days
Rome (&lt;a href=&quot;https://loige.link/rust-lambda-ws&quot;&gt;Slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;12-13: The role of the serverless dev (Panel), Serverless Days Rome&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This brings my total number of talks to &lt;strong&gt;157&lt;/strong&gt; in 2024. Crazy to think I have
done so many!&lt;/p&gt;
&lt;p&gt;If you are curious to see the full list and check out videos and slides, you can
find them all in the &lt;a href=&quot;/speaking&quot;&gt;speaking section&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also worth mentioning that I attended re:Invent again this year, and it was a
blast! I got to meet so many amazing people from the incredible AWS community
and learned a ton from them. Here’s a randomly selected picture!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Luciano at re:Invent in a group picture with Anurag Kale, Ivan Casco Valero, and Marcus Bladh&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2048&quot; height=&quot;1536&quot; src=&quot;https://loige.co/_astro/luciano-at-reinvent-2024-in-las-vegas.BnEkdF4u_Z2hpxrk.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;From left to right:
&lt;a href=&quot;https://www.linkedin.com/in/anuragkale/&quot;&gt;Anurag Kale&lt;/a&gt;,
&lt;a href=&quot;https://www.linkedin.com/in/ivancasco/&quot;&gt;Ivan Casco Valero&lt;/a&gt;,
&lt;a href=&quot;https://www.linkedin.com/in/marcus-bladh/&quot;&gt;Marcus Bladh&lt;/a&gt;, it’s a me!&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;In 2025, I think I will deliberately slow down a bit on the speaking front. I
want to reduce the amount of travel and focus more on other side projects, but I
will probably still be speaking at a few conferences. So if you want to invite
me to speak at your event (especially if it’s a remote one), please
&lt;a href=&quot;http://loige.link/invite-me-to-a-conference&quot;&gt;reach out to me&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;No grand idea was ever born in a conference, but a lot of foolish ideas have
died there.&lt;br&gt;
— F. Scott Fitzgerald&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;nodejs-design-patterns-still-a-relevant-resource-after-all-these-years&quot;&gt;Node.js Design Patterns: Still a Relevant Resource After All These Years&lt;/h2&gt;
&lt;p&gt;Even after four years on the shelves (and in online stores), the third edition
of &lt;a href=&quot;https://www.nodejsdesignpatterns.com/&quot;&gt;Node.js Design Patterns&lt;/a&gt; is still
going quite strong. We’re still getting plenty of good reviews and hearing from
happy readers.&lt;/p&gt;
&lt;p&gt;We are currently holding a solid 4.6 stars with over 300 reviews on Amazon! It’s
incredibly rewarding to know that our work is still helping developers improve
their skills.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Node.js Design Patterns Third Edition on Amazon&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1089&quot; height=&quot;471&quot; src=&quot;https://loige.co/_astro/node-js-design-patterns-screenshot-from-amazon.4zi6V9fl_1mpjhz.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;In 2024, we even had some great people in the JavaScript community talking about
the book, which gave it another boost in visibility. A huge thank you to
everyone who has recommended it to others!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/posts/mapocock_ready-for-my-node-era-activity-7220713835978993664-l96k/&quot;&gt;&lt;img alt=&quot;Matt Pocock (Total TypeScript) showcasing his copy of Node.js Design Patterns on LinkedIn&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;455&quot; height=&quot;681&quot; src=&quot;https://loige.co/_astro/matt-pocock-showcasing-his-copy-of-nodejs-design-patterns.C9sDTCiz_22GoYj.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Matt Pocock (Total TypeScript) showcasing his copy of Node.js Design
Patterns on LinkedIn&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;Because the book features Node.js 14, many people ask if it’s still up-to-date
and relevant. My answer is absolutely yes! All the patterns we focus on are
pretty much timeless, and if you’re just starting with Node.js and JavaScript
and want to ramp up your knowledge, there’s still plenty to learn from it.&lt;/p&gt;
&lt;p&gt;Of course, there have been some minor improvements in the Node.js and JavaScript
landscape since this edition was launched, so there might be a few opportunities
here and there to make the book even more relevant and up-to-date. I cannot
disclose anything specific right now, but I can only say: stay tuned! 😉&lt;/p&gt;
&lt;p&gt;Meanwhile, if you’ve read the book and appreciated it, please leave us a review
on Amazon or Goodreads. This is the single best thing you can do to help us and
encourage us to invest more in this kind of activity. Your feedback means the
world to us!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The future of publishing is about having connections to readers and the
knowledge of what those readers want.&lt;br&gt;
— Seth Godin&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;aws-bites-still-serving-up-serverless-goodness-now-in-bi-weekly-portions&quot;&gt;AWS Bites: Still Serving Up Serverless Goodness (Now in Bi-Weekly Portions!)&lt;/h2&gt;
&lt;p&gt;AWS Bites, the weekly podcast that
&lt;a href=&quot;https://bsky.app/profile/eoin.sh&quot;&gt;Eoin Shanagy&lt;/a&gt; and I started in 2021, is now
in its fourth season, and we’re still going quite strong! 💪&lt;/p&gt;
&lt;p&gt;While we reduced our publishing frequency this year from weekly to bi-weekly, we
still managed to release 29 new episodes packed with AWS and serverless
insights.&lt;/p&gt;
&lt;p&gt;Looking at the stats provided by Spotify, we reached &lt;strong&gt;140k plays&lt;/strong&gt; with an
average of &lt;strong&gt;775 listeners per episode&lt;/strong&gt;, which I think is quite rewarding.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Stats for AWS Bites podcast in 2024 from Spotify&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2466&quot; height=&quot;1594&quot; src=&quot;https://loige.co/_astro/aws-bites-spotify-stats-2024.DixAFGDv_2pWQB9.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;On YouTube, we have &lt;strong&gt;3800 subscribers&lt;/strong&gt; and almost &lt;strong&gt;50k views&lt;/strong&gt; in 2024 alone!
Thank you to everyone who listens and watches! 🙏&lt;/p&gt;
&lt;p&gt;The episodes that people seem to have enjoyed the most are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On YouTube:
&lt;a href=&quot;https://awsbites.com/111-how-we-run-a-cloud-consulting-business/&quot;&gt;Ep. 111 - How We Run a Cloud Consulting Business&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;On Spotify:
&lt;a href=&quot;https://awsbites.com/120-lambda-best-practices/&quot;&gt;Ep. 120 - Lambda Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Another cool thing we did in 2024 was to bring in more people from fourTheorem.
We had the pleasure of having our CFO, &lt;strong&gt;Fiona McKenna&lt;/strong&gt;, to discuss
&lt;a href=&quot;https://awsbites.com/133-building-businesses-in-the-cloud-with-fiona-mckenna&quot;&gt;the financial
aspects of running a cloud consulting business&lt;/a&gt;.
We also had &lt;strong&gt;Conor Maher&lt;/strong&gt; to talk about
&lt;a href=&quot;https://awsbites.com/134-eliminate-the-iam-user/&quot;&gt;how to get rid of those annoying IAM users
and improve the security and governance of AWS Accounts&lt;/a&gt;,
and &lt;strong&gt;David Lynam&lt;/strong&gt; talking about
&lt;a href=&quot;https://awsbites.com/137-transit-gateway-explained/&quot;&gt;AWS Transit Gateway&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We were also super pleased to have had the opportunity to interview the one and
only &lt;a href=&quot;https://bsky.app/profile/farrah.bsky.social&quot;&gt;Farrah Campbell&lt;/a&gt; and get her
to share her history and some suggestions for people who want to grow in tech.
If you are curious to know more, check out
&lt;a href=&quot;https://awsbites.com/130-growing-in-tech-with-farrah-campbell/&quot;&gt;Ep. 130 - Growing in Tech with Farrah Campbell&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;AWS Bites is something we will surely keep investing on in 2025 because we think
it’s providing value to the AWS Community, and it’s a great place for us to
share what we learn every day while working with AWS.&lt;/p&gt;
&lt;p&gt;If there’s a topic you think we should cover, or if you have any piece of
feedback you want to share with us, please reach out and let us know! We’re
always looking for new ideas.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You’re going to be terrible at a lot of things for years until you’re
successful. People probably aren’t going to listen to your podcast initially.
But if you like it and you keep putting it out, people will find it.&lt;/p&gt;
&lt;p&gt;— Keith Kingbay&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;middy-still-the-leading-middleware-framework-for-aws-lambda&quot;&gt;Middy: Still the Leading Middleware Framework for AWS Lambda&lt;/h2&gt;
&lt;p&gt;Middy is a Node.js middleware framework specifically designed for AWS Lambda! I
started this project during the early days of Lambda around 2015 (even though
the very first public commit only happened on August 3, 2017), and it’s been
quite a journey.&lt;/p&gt;
&lt;p&gt;Although, a few years back I found myself struggling with maintainer duties, and
I passed the ball to &lt;a href=&quot;https://github.com/willfarrell&quot;&gt;Will Farrell&lt;/a&gt;, one of the
most active contributors, who has since stepped in as a maintainer (and has done
a far better job than I could ever dream of doing!).&lt;/p&gt;
&lt;p&gt;So today, anything you see happening around Middy is Will’s merit. I only like
to talk about it to see how the project is doing, but I can’t really claim any
credit! I only have a few occasional chats per year with Will, so you could say
I have a very distant role as an advisor, at best…&lt;/p&gt;
&lt;p&gt;The main news of 2024 is that
&lt;a href=&quot;https://github.com/middyjs/middy/releases/tag/6.0.0&quot;&gt;Middy v6.0.0&lt;/a&gt; was released
in November, bringing the following to the table:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deprecation of Node.js v18.x&lt;/li&gt;
&lt;li&gt;Addition of support for Node.js v22.x&lt;/li&gt;
&lt;li&gt;Addition of support for &lt;code&gt;--experimental-require-module&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to read the full list of changes and how to upgrade from v5, check
out
&lt;a href=&quot;https://middy.js.org/docs/upgrade/5-6&quot;&gt;the official Middy 5 to 6 migration guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In terms of stats, Middy is still the leading middleware framework for AWS
Lambda in the JavaScript/TypeScript landscape, with an average of &lt;strong&gt;360k
downloads per week&lt;/strong&gt; (of the core module alone). It’s awesome to see such
continued adoption!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://npmtrends.com/@codegenie/serverless-express-vs-@fastify/aws-lambda-vs-@middy/core-vs-@vendia/serverless-express-vs-aws-lambda-fastify-vs-aws-serverless-express-vs-lambda-api-vs-serverless-express-vs-serverless-http&quot;&gt;&lt;img alt=&quot;Download chart showcasing how middy compares to other frameworks in the space&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2706&quot; height=&quot;1004&quot; src=&quot;https://loige.co/_astro/middy-vs-other-frameworks-downloads-chart.BnyCnfhE_Z1Cg3ih.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It has almost reached &lt;strong&gt;4000 stars on GitHub&lt;/strong&gt; (3762 right now), so if you like
Middy and want to give us a little hand,
&lt;a href=&quot;https://github.com/middyjs/middy&quot;&gt;give it a star on GitHub&lt;/a&gt; – it costs nothing!
Make sure to also reach out to Will and
&lt;a href=&quot;https://github.com/sponsors/willfarrell&quot;&gt;consider sponsoring&lt;/a&gt; him to support
his incredible work (not just about Middy). He’s the one putting in the hard
work to keep Middy going strong.&lt;/p&gt;
&lt;p&gt;I have yet to catch up with Will in detail, but from what I could tell, his
focus for this year will be on security hardening, stability, and improving the
open-source processes around the management of the project. These are all great
priorities to keep Middy a robust and trustworthy framework.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Software is a great combination between artistry and engineering.&lt;/p&gt;
&lt;p&gt;— Bill Gates&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;streaming-technology-and-learning-rust-on-twitch-fun-experiments-and-hopefully-some-learning&quot;&gt;Streaming Technology and Learning Rust on Twitch: Fun, Experiments, and (Hopefully) Some Learning&lt;/h2&gt;
&lt;p&gt;In 2024, I kept streaming
&lt;a href=&quot;https://twitch.tv/loige&quot;&gt;live coding sessions on Twitch&lt;/a&gt; with my dear friend
&lt;a href=&quot;https://twitter.com/gbinside&quot;&gt;Roberto&lt;/a&gt;. These streams have become a great way
for us to explore new technologies, learn together, and generally geek out about
code.&lt;/p&gt;
&lt;p&gt;We completed a few interesting projects this year, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PLbNOKnE-Oyr2gyJyDsFgVIoFl5fz0D7zL&quot;&gt;Building a parser for the REDIS protocol using the parser combinator nom&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PLbNOKnE-Oyr1BCduX_69Nt97CozZC3uW7&quot;&gt;Building an MVP for a lead generation system only using Rust, Lambda, DynamoDB,
and SES on AWS (tinykit)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PLbNOKnE-Oyr2RgIPBjghBQqfmFBogW5zH&quot;&gt;Building a BitTorrent client using Rust&lt;/a&gt;
following one of the
&lt;a href=&quot;https://app.codecrafters.io/join?via=lmammino&quot;&gt;CodeCrafters&lt;/a&gt; guided tutorials&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://www.youtube.com/embed/videoseries?si=jmqyqALqfEFb3R2U&amp;#x26;list=PLbNOKnE-Oyr2gyJyDsFgVIoFl5fz0D7zL&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Overall, I don’t think we had a massive growth in terms of following or views
and I don’t even care enough to check the numbers because this honestly isn’t
why we do these streams. We just do them to have an excuse to keep experimenting
and learning together, and so far, I think this has been working pretty well for
us. It’s more about the journey than the destination!&lt;/p&gt;
&lt;p&gt;So, we’ll probably keep these going on a semi-consistent frequency in 2025. If
you’re interested in hanging out with us during these sessions,
&lt;a href=&quot;https://twitch.tv/loige&quot;&gt;check us out on Twitch&lt;/a&gt;. Otherwise, you can check out
all our recordings on &lt;a href=&quot;https://www.twitch.tv/loige&quot;&gt;my YouTube Channel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Come learn Rust with us (and maybe teach us a thing or two)!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tell me and I forget, teach me and I may remember, involve me and I learn.&lt;/p&gt;
&lt;p&gt;— Benjamin Franklin&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;my-open-source-work-in-2024&quot;&gt;My Open Source work in 2024&lt;/h2&gt;
&lt;p&gt;I always like to do some open source whenever I have the chance. I like to
contribute to projects I use (even in small ways) and I like to share almost
everything I do in an open-source fashion.&lt;/p&gt;
&lt;p&gt;Looking back at my GitHub history, I actually did &lt;em&gt;way&lt;/em&gt; more than I originally
thought, so it’s probably a good thing to do this kind of reflection to see how
much I did actually accomplish over the year! It’s easy to lose track of the
smaller contributions, but they all add up.&lt;/p&gt;
&lt;p&gt;Here’s a summary of my main open-source contributions of 2024:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cargo-lambda/default-template/pull/10&quot;&gt;Small contributions to Cargo Lambda&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;I created &lt;a href=&quot;https://github.com/lmammino/fm.loige.co&quot;&gt;fm.loige.co&lt;/a&gt;, a simple
Rust and Lambda powered API to display the song that I am currently listening
to on this very website (in the &lt;a href=&quot;/&quot;&gt;home page&lt;/a&gt;). It’s powered by Last.fm&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/tinyresp&quot;&gt;Tinyresp&lt;/a&gt;, a parser for the Redis
protocol written as a Rust library&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/mailchimp-list-janitor&quot;&gt;Mailchimp List Janitor&lt;/a&gt;:
a Rust based tool that allows you to remove unsubscribed users from your
Mailchimp lists and save money in the process (a bit in an incomplete state)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/obs-countdown&quot;&gt;OBS-countdown&lt;/a&gt;: A Rust-powered CLI
tool that allows you to manage a countdown file that you can use to display a
countdown in OBS&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/mvp-activities&quot;&gt;MVP Activities&lt;/a&gt;: A simple client
to interact with the Microsoft MVP activities API (not official)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nodejs/nodejs.org/pull/6495&quot;&gt;A small contribution to the new Node.js website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/oidc-authorizer&quot;&gt;oidc-authorizer&lt;/a&gt;: A
high-performance token-based API Gateway authorizer Lambda that can validate
OIDC-issued JWT tokens. It’s written in Rust and it also comes with a repo for
the &lt;a href=&quot;https://github.com/lmammino/oidc-authorizer-benchmark&quot;&gt;benchmarks&lt;/a&gt;
against a python-based alternative&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/tinykit&quot;&gt;Tinykit&lt;/a&gt;, a super simple and mostly
incomplete lead magnet system written using Rust and Lambda&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/svg-invert&quot;&gt;svg-invert&lt;/a&gt;: A simple Rust-based CLI
utility that inverts colors in an SVG file:&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/awslabs/cloudfront-hosting-toolkit/pull/10&quot;&gt;A Small contribution to the AWS cloudfront-hosting-toolkit project&lt;/a&gt;
to make their CI a bit faster&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/org-formation-sso-import&quot;&gt;org-formation-sso-import&lt;/a&gt;:
A TypeScript based CLI tool to import AWS SSO groups, permission sets and
assignments into an OrgFormation workspace&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/awsbites/aws-bites-site/pull/200&quot;&gt;Added free text search on the AWS Bites website&lt;/a&gt;
using Orama&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/rust-lambda-workshop-ext&quot;&gt;A rust + Lambda workshop&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;A screenshot of my GitHub contribution chart in 2024, slightly skewed because it&amp;amp;#x27;s Feb
2025 😉&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2104&quot; height=&quot;562&quot; src=&quot;https://loige.co/_astro/lmammino-github-contributions-chart-2024.DDpVx0Vt_2r59UC.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Here’s a screenshot of my GitHub contribution chart, just for vanity, although
it’s slightly skewed in time since I am taking this in Feb 2025 😉&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The power of Open Source is the power of the people. The people rule.&lt;/p&gt;
&lt;p&gt;— Philippe Kahn&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;articles--blog&quot;&gt;Articles &amp;#x26; Blog&lt;/h2&gt;
&lt;p&gt;I didn’t write very much on this blog in 2024. I only managed to publish 3
articles. Quality over quantity, right? 😉&lt;/p&gt;
&lt;p&gt;However, I &lt;em&gt;did&lt;/em&gt; spend a good bit of my free time between the end of 2023 and
the beginning of 2024 migrating the technology that powers this blog from Gatsby
to Astro. If you want to find out more about the motivation and the migration
process, well, that’s one of the three articles I wrote:
&lt;a href=&quot;/migrating-from-gatsby-to-astro&quot;&gt;Migrating from Gatsby to Astro&lt;/a&gt;. It was a fun
project that should lead to better performance and easier maintenance in the
future. And in the process I also redesigned the look and feel entirely. I hope
you like it! …and be careful of the &lt;a href=&quot;/404&quot;&gt;dreadful 404 page&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The new hero banner on the newly-designed home page&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;544&quot; src=&quot;https://loige.co/_astro/loige-co-home-page-banner-redesign.VM4w4ySJ_dTFXR.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;The new hero banner on the newly-designed home page. Note how it displays
what I am listening to in real-time 🎸&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;The other two articles are about
&lt;a href=&quot;/404-newsletter-found&quot;&gt;how I Have Published 404 Issues of a Newsletter for Full-Stack Developers Over the Last 8 Years&lt;/a&gt;
and announcing that
&lt;a href=&quot;/coauthoring-a-book-about-rust-and-lambda&quot;&gt;I am co-authoring a book about Rust and Lambda&lt;/a&gt;.
So, you can see that while the output was low, the topics were significant for
me.&lt;/p&gt;
&lt;p&gt;Will I write more in 2025? I don’t know… This &lt;em&gt;is&lt;/em&gt; the first article of the
year, so maybe it’s a good start! I’m not planning to have a particular
schedule, so we’ll see what inspiration strikes. Stay tuned!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The best time to plant a tree was 20 years ago. The second best time is now&lt;/p&gt;
&lt;p&gt;— Chinese Proverb&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;fullstack-bulletin-eight-years-and-more-than-404-published-issues&quot;&gt;FullStack Bulletin: Eight Years and more than 404 published Issues&lt;/h2&gt;
&lt;p&gt;In 2024, FullStack Bulletin reached a significant milestone: issue 404! It’s
hard to believe it’s been eight years since I embarked on this project, aiming
to make sense of the fast-paced, ever-evolving world of full-stack web
development.&lt;/p&gt;
&lt;p&gt;If you’re curious about the story behind the newsletter – why I created it, the
technical architecture, and my vision for the future – you can read all about it
in my article
&lt;a href=&quot;/404-newsletter-found&quot;&gt;How I Have Published 404 Issues of a Newsletter for Full-Stack Developers Over the Last 8 Years&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But, to give you a short summary, FullStack Bulletin is a weekly newsletter
designed to keep developers informed and inspired. Every week, I curate a
selection of articles, a recommended book, and a thought-provoking quote, all
tailored for full-stack developers and those aspiring to join the field. It’s
the newsletter I wish I had when I started my own full-stack development
journey. Andrea Mangano and I originally designed the format together and Andrea
is responsible for the awesome look and feel that still represents FullStack
Bulletin today.&lt;/p&gt;
&lt;p&gt;I have had this quote in the article to celebrate the history. “FullStack
Bulletin is our way of making life a bit easier for full-stack developers and
those aspiring to join the field. Every week, we carefully curate the most
interesting and valuable content, delivering it straight to your inbox. Since
our launch in March 2017, our mission has been to help developers stay informed
and inspired.”&lt;/p&gt;
&lt;p&gt;Since last year, we’re still at around 3000 subscribers, so the growth has been
very flat. This isn’t an encouraging sign, but at the same time, I keep getting
good feedback from readers, which is what keeps me going.&lt;/p&gt;
&lt;p&gt;In 2024, I also decided to give every newsletter a more personal touch, adding
an editorial intro where I can share some of my personal news and encourage
people to keep being inspired by the awesome content you can freely find on the
web. I also spend more time making sure every piece of content has a good
description that highlights why I handpicked that particular link.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A screenshot of an issue of FullStack Bulletin&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2048&quot; height=&quot;2059&quot; src=&quot;https://loige.co/_astro/fullstack-bulletin-screenshot.DYxYIP-r_2s7U9h.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;People seem to have appreciated this more personal touch, so that’s probably a
good sign. This year, I am considering moving FSB away from Mailchimp and
adopting another provider. If you have any suggestions, let me know! I’m always
open to finding a more cost-effective and feature-rich platform. And if you’re
not already a subscriber, you can sign up at
&lt;a href=&quot;https://fullstackbulletin.com/&quot;&gt;FullStackBulletin.com&lt;/a&gt; and join our wonderful
community.&lt;/p&gt;
&lt;p&gt;A particularly big shout-out goes to one of our major sponsors last year:
&lt;a href=&quot;https://posthog.com/&quot;&gt;PostHog&lt;/a&gt;. Thanks for supporting us.&lt;/p&gt;
&lt;p&gt;By the way, we are looking for new sponsors, so if you have a company that
targets full-stack developers, let me know. I have a nice slide deck I can share
with you that illustrates the sponsorship process and the costs in a
super-simple way.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Human beings are curators. Each polishes his or her own favoured memories,
arranging them in order to create a narrative that pleases.&lt;/p&gt;
&lt;p&gt;— Kate Morton&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;other-stuff-personal-achievements-and-looking-ahead&quot;&gt;Other Stuff: Personal Achievements and Looking Ahead&lt;/h2&gt;
&lt;p&gt;Now, onto some other more personal achievements of 2024 🦸🏻. It’s important to
remember that life isn’t just about code, conferences, books, podcasts and
newsletters! 😆&lt;/p&gt;
&lt;p&gt;I have been quite bad at running this year, totaling only &lt;strong&gt;9 runs&lt;/strong&gt; for a total
of &lt;strong&gt;~60Km&lt;/strong&gt;. I definitely need to improve that in 2025! However, I have been
pretty consistent with Brazilian Jiu-Jitsu training, practicing for almost 100
sessions during 2024 and reaching the grade of &lt;strong&gt;purple belt with 2 stripes&lt;/strong&gt;!
🥋 Thanks to all my teammates and professors for keeping me engaged and
motivated (although I doubt any of them will ever read this page 😅).&lt;/p&gt;
&lt;p&gt;… And in general I kept myself fit, training more at home, getting in better
shape and eating healthier! That’s something I’m proud of and I can see making
me a lot happier and productive. 💪&lt;/p&gt;
&lt;p&gt;Finally, I want to mention I had a lovely road trip to the Norway fjords with my
wife during the summer. It was absolutely stunning, and a great way to recharge.
I’ll leave you with a random picture from this trip.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A picture of the Norway fjords&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://loige.co/_astro/norway-fjords.BA8bGe0M_Z1skSEP.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;That’s all, folks! Please comment to let me know what was your biggest
achievement of 2024 and what do you plan to do in 2025. I’m always curious to
hear what others are working on.&lt;/p&gt;
&lt;p&gt;See you in the next article, hopefully soon! 😉&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/2024-a-year-in-review.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/2024-a-year-in-review.png" width="1200" height="630"/></media:content><category>life</category><author>Luciano Mammino</author><comments>https://loige.co/2024-a-year-in-review/#comments</comments><enclosure url="https://loige.co/og/2024-a-year-in-review.png" length="0" type="image/png"/></item><item><title>Node.js Design Patterns: Fourth Edition is out!</title><link>https://loige.co/nodejs-design-patterns-fourth-edition/</link><guid isPermaLink="true">https://loige.co/nodejs-design-patterns-fourth-edition/</guid><description>The fourth edition of Node.js Design Patterns is here. As one of the authors, I share why we wrote a new edition, what&apos;s new, and my thoughts on where Node.js is heading.</description><pubDate>Thu, 18 Dec 2025 11:22:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ll admit it: I’m a few months late writing this. The fourth edition of Node.js Design Patterns has been out since September 25, 2025, and here I am in December finally getting around to the announcement post. But as they say, better late than never!&lt;/p&gt;
&lt;p&gt;Rather than just telling you “hey, new book, go buy it,” I wanted to use this article to offer something more valuable: a first-person perspective from one of the authors. I’ll share why Mario and I decided to write a new edition, what we believe this book provides, and (perhaps more interestingly) some broader thoughts on where the Node.js ecosystem is heading. Whether you end up buying the book or not, I hope you’ll find some useful insights here.&lt;/p&gt;
&lt;h2 id=&quot;what-is-nodejs-design-patterns&quot;&gt;What is Node.js Design Patterns?&lt;/h2&gt;
&lt;p&gt;Node.js Design Patterns is a book authored by &lt;strong&gt;Mario Casciaro&lt;/strong&gt; and &lt;strong&gt;Luciano Mammino&lt;/strong&gt; (that’s me). It is probably the most well-known print book when it comes to mastering Node.js. The first edition came out in 2014, more than a decade ago, when Node.js was still at version 0.10. It’s fair to say this book has been tracking the evolution of Node.js for its entire journey from scrappy newcomer to production-grade platform.&lt;/p&gt;
&lt;p&gt;Over the years, the book has helped tens of thousands of developers worldwide and has been translated into multiple languages. It’s become a trusted resource for teams onboarding new developers and for individuals looking to level up their Node.js skills.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Person reading Node.js Design Patterns (Fourth Edition), with the new edition’s cover clearly visible.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;666&quot; src=&quot;https://loige.co/_astro/person-holding-and-reading-nodejs-design-patterns.BV1H56AS_Z1VtSl.webp&quot; &gt;&lt;/p&gt;
&lt;h3 id=&quot;a-personal-story-how-i-became-a-co-author&quot;&gt;A personal story: how I became a co-author&lt;/h3&gt;
&lt;p&gt;Let me share a bit of my own journey with Node.js, because I think it illustrates something important about what this book aims to do.&lt;/p&gt;
&lt;p&gt;As a web developer, I had a solid background in frontend JavaScript (yes, lots of jQuery!). When I discovered Node.js (version 0.12 at the time), I was excited about the possibility of using JavaScript on the backend and potentially replacing the other languages I was working with, like PHP, Java, and .NET.&lt;/p&gt;
&lt;p&gt;I started learning Node.js with the first edition of this very book, which Mario had authored solo. After finishing it, I was eager to build something real. So I took on a personal project: downloading an entire photo gallery from Flickr (a popular photo hosting site at the time). Flickr didn’t offer a way to download all your photos in one go, so I decided to use its API and my new Node.js skills to create a CLI tool that could do just that.&lt;/p&gt;
&lt;p&gt;This project was the perfect opportunity to leverage Node.js’s asynchronous nature. Downloading hundreds of files from URLs is ideal for concurrency. There’s no reason to fetch them one by one when you can download several at once. However, doing this effectively required limiting concurrency to avoid overwhelming system resources like memory and network bandwidth.&lt;/p&gt;
&lt;p&gt;After building the tool, I &lt;a href=&quot;https://github.com/lmammino/flickr-set-get&quot;&gt;shared the project on GitHub&lt;/a&gt; and sought feedback from various Node.js communities. And I got a lot of feedback! Many people pointed out that while my code worked, it didn’t fully embrace the “Node way.” My approach still had traces of a PHP-like style, which made it harder to integrate smoothly with the broader Node.js ecosystem.&lt;/p&gt;
&lt;p&gt;That feedback was invaluable. It helped me improve my Node.js skills and understand the importance of adopting its design principles. And here’s a fun twist: Mario was one of the people who gave me feedback on that project! That interaction, plus some other serendipitous life events, sparked a connection between us, which eventually led to me joining him as a co-author for the second edition a few years later.&lt;/p&gt;
&lt;p&gt;So maybe there’s a lesson here: don’t be afraid to share your work and ask for candid feedback. The Node.js community is supportive and helpful, providing countless opportunities to learn and grow. Who knows where those opportunities might lead!&lt;/p&gt;
&lt;h2 id=&quot;who-is-this-book-for&quot;&gt;Who is this book for?&lt;/h2&gt;
&lt;p&gt;Let me be upfront: this is not a beginner’s book. We don’t explain JavaScript syntax or walk you through setting up your first Node.js project. We assume you already have some prior knowledge and at least a degree of familiarity with JavaScript. If you’re comfortable writing functions, working with objects and arrays, and have dabbled with Node.js even just a little, you have enough foundation to get started.&lt;/p&gt;
&lt;p&gt;Our goal is to take those foundations and elevate you to become a reliable professional in the Node.js space. Someone who can build with confidence, accounting for performance, security, scalability, and evolvability.&lt;/p&gt;
&lt;p&gt;Throughout the book, you’ll walk through carefully crafted code examples, learn how to master asynchronous flows, write clean and testable code, and apply battle-tested design and architectural patterns that scale.&lt;/p&gt;
&lt;p&gt;From modular design and dependency injection to scalability, messaging, and integration patterns: this is the bread and butter of senior developers who build complex, distributed systems with confidence.&lt;/p&gt;
&lt;h2 id=&quot;why-a-new-edition&quot;&gt;Why a new edition?&lt;/h2&gt;
&lt;p&gt;We held off on releasing a new edition for a while. We genuinely believed (and still believe) that the third edition remains extremely relevant for what it teaches. The core patterns and principles don’t change with every Node.js release.&lt;/p&gt;
&lt;p&gt;But we also recognized that in the last two to three years, the Node.js ecosystem has sprinted forward quite a bit. There have been a number of significant shifts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Stable ESM support&lt;/strong&gt;: ECMAScript modules are now first-class citizens in Node.js&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integrated test runner&lt;/strong&gt;: Testing has become a built-in capability, not just a third-party concern&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A more “batteries-included” standard library&lt;/strong&gt;: Native support for &lt;code&gt;fetch&lt;/code&gt;, better file system APIs, and more&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improved Promise and async/await support&lt;/strong&gt;: The standard library has embraced modern async patterns throughout&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We wanted to make sure this resource was up to date with this evolution. We also took the opportunity to incorporate feedback we’ve been receiving over the years: more mentions of TypeScript, expanded coverage of security, and practical production-ready tips.&lt;/p&gt;
&lt;p&gt;Our goal remains the same: give you a progressive journey into becoming a senior Node.js developer who can ship with confidence. The book can be read from beginning to end, following the progression from fundamentals to advanced architecture, or you can keep it at your side as a long-term reference. Each chapter blends theory with practical examples and exercises, so you can put what you’ve learned into practice immediately.&lt;/p&gt;
&lt;p&gt;This fourth edition is fully updated for Node.js 24, features modern JavaScript throughout (ECMAScript modules and async/await), includes a brand-new chapter dedicated to testing, and offers expanded coverage of scalability, security, and architecture for today’s production environments.&lt;/p&gt;
&lt;h2 id=&quot;what-the-book-covers&quot;&gt;What the book covers&lt;/h2&gt;
&lt;p&gt;The book is organized into 13 chapters that take you on a journey from Node.js fundamentals to distributed systems architecture:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The Node.js Platform&lt;/strong&gt;: Understanding the runtime, the event loop, and what makes Node.js tick&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Module System&lt;/strong&gt;: ESM, CommonJS, and modern patterns for organizing code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Callbacks and Events&lt;/strong&gt;: The foundational patterns that everything else builds upon&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Asynchronous Control Flow Patterns with Callbacks&lt;/strong&gt;: Managing complexity in callback-based code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Asynchronous Control Flow Patterns with Promises and Async/Await&lt;/strong&gt;: Modern async patterns&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coding with Streams&lt;/strong&gt;: Our favorite chapter… and it’s free! More on this later!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Creational Design Patterns&lt;/strong&gt;: Factory, Builder, Singleton, and more&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Structural Design Patterns&lt;/strong&gt;: Proxy, Decorator, Adapter patterns in JavaScript&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Behavioral Design Patterns&lt;/strong&gt;: Strategy, State, Template, Iterator, and beyond&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Testing: Patterns and Best Practices&lt;/strong&gt;: &lt;strong&gt;NEW in this edition!&lt;/strong&gt; Unit, integration, and E2E testing strategies&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advanced Recipes&lt;/strong&gt;: Real-world techniques for common challenges&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scalability Patterns&lt;/strong&gt;: Clustering, load balancing, and scaling strategies&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Messaging and Integration Patterns&lt;/strong&gt;: Building distributed systems that communicate effectively&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;What’s new in this edition:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Testing chapter&lt;/strong&gt; is entirely new. We’re thrilled that testing has become a first-class citizen in Node.js with the built-in test runner, and we wanted to give it the attention it deserves.&lt;/li&gt;
&lt;li&gt;All content has been updated for &lt;strong&gt;Node.js 24&lt;/strong&gt; and modern JavaScript features&lt;/li&gt;
&lt;li&gt;Expanded coverage of &lt;strong&gt;security&lt;/strong&gt; and &lt;strong&gt;production-readiness&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;More &lt;strong&gt;TypeScript&lt;/strong&gt; references and considerations throughout&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One chapter we decided to remove is the one on &lt;strong&gt;Universal (or isomorphic) JavaScript&lt;/strong&gt;. While we believe that was a very interesting topic, we also recognize that the world of Universal JavaScript has evolved quite a bit. React has become more of a full-stack framework with Next.js and similar tools reshaping how we think about server-side rendering and code sharing between client and server. We recognized this has become a massive topic on its own and it would be hard to cover it properly, especially considering it’s still a rapidly evolving field. Plus, the book in its new shape is already more than 700 pages, so we had to cut something!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Hands holding a tablet showing a page from Node.js Design Patterns, with highlighted code examples visible.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;750&quot; src=&quot;https://loige.co/_astro/reading-nodejs-design-patterns-on-a-white-ipad-sitting-park.DIn7NYTh_Z1qNtTe.webp&quot; &gt;&lt;/p&gt;
&lt;h2 id=&quot;how-to-approach-the-book&quot;&gt;How to approach the book&lt;/h2&gt;
&lt;p&gt;We structured the book as a learning journey, not just a random collection of chapters. Start from how Node.js really works (the event loop, the async model), then move into patterns, testing, scalability, microservices, and messaging.&lt;/p&gt;
&lt;p&gt;Each topic mixes theory, practical examples, and exercises so you build a solid mental model and immediately try it out in code. The examples are realistic and grounded in the kinds of problems you’ll face in production. The exercises give you the opportunity to test your understanding and refine your skills.&lt;/p&gt;
&lt;p&gt;Many readers have told us their ideal path was to read it from beginning to end once, then keep it as a reference to deep dive into specific chapters or patterns when they face those problems at work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The journey we had in mind:&lt;/strong&gt; We start from “I can ship Node code” and aim for “I can design and maintain production-grade Node systems.” We follow a deliberate structure:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Runtime fundamentals&lt;/li&gt;
&lt;li&gt;Patterns inside a single service&lt;/li&gt;
&lt;li&gt;Patterns across services and distributed systems.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;The big mindset shift we hope you’ll experience:&lt;/strong&gt; A more deliberate, conscious approach to Node.js. Know the tools the platform gives you and when to reach for each one. Develop a concrete sense of what “production-ready” means in Node:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Code that is readable and maintainable&lt;/li&gt;
&lt;li&gt;Code that is secure&lt;/li&gt;
&lt;li&gt;Code that is continuously tested&lt;/li&gt;
&lt;li&gt;Code that can scale because it respects the event loop and uses the right concurrency and architecture patterns&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;our-favorite-chapter-nodejs-streams-is-free&quot;&gt;Our favorite chapter (Node.js streams) is free&lt;/h2&gt;
&lt;p&gt;Chapter 6, “Coding with Streams,” is my personal favorite. We believe in it so much that we give it away for free on &lt;a href=&quot;https://nodejsdesignpatterns.com/&quot;&gt;the official Node.js Design Patterns website&lt;/a&gt;. It’s about 80 pages of in-depth coverage of one of Node.js’s most powerful features.&lt;/p&gt;
&lt;p&gt;Streams have been there since the early days and power a big chunk of the standard library (HTTP, file system, process I/O). Yet they’re still one of the most misunderstood and underused features in the ecosystem.&lt;/p&gt;
&lt;p&gt;I revisit this chapter a lot because streams are where Node.js really shines for serious, data-heavy backend work. They’re not trivial to learn, and historically there hasn’t been great, cohesive material on them. We wanted this chapter to finally make streams “click” for people.&lt;/p&gt;
&lt;p&gt;Streams are also one of the most unique characteristics of Node.js. Other languages and runtimes have streaming abstractions, but I haven’t seen another ecosystem where the concept is so complete, integrated, and pervasive across the core APIs. As someone who works with many different programming languages, Node.js streams are always the first thing I miss when I switch to Python, .NET, or Java. I genuinely wish other ecosystems had something similar.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Here’s a controversial take from that chapter:&lt;/strong&gt; The main value of streams is not “making things faster” (although sometimes that’s the case and it can be a nice side effect). The real superpower is &lt;strong&gt;keeping memory usage constant&lt;/strong&gt; while moving huge or even unbounded amounts of data. Streams let you handle gigabytes, terabytes, or even infinite sources like sensor data, with only small chunks in memory at any time.&lt;/p&gt;
&lt;p&gt;The tradeoff is a different mindset: you never have “all the data,” only the current chunk. You need to think in terms of incremental progress and smart buffering instead of “load everything and then process.” Once that clicks, you start seeing streams as a fundamental design tool, not just an optimization trick.&lt;/p&gt;
&lt;p&gt;If that chapter resonates with you, you’ll see how much more there is to gain from the rest of the book. &lt;a href=&quot;https://nodejsdesignpatterns.com/#free-chapter&quot;&gt;Download it for free&lt;/a&gt; and see for yourself.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Open Node.js Design Patterns book on a desk, showing Chapter 6 “Coding with Streams.”&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;666&quot; src=&quot;https://loige.co/_astro/person-holding-and-reading-node-js-design-patterns-chapter-6-streams.B-Mhj_7Y_2anSv5.webp&quot; &gt;&lt;/p&gt;
&lt;h2 id=&quot;whats-happening-in-nodejs-and-why-it-matters&quot;&gt;What’s happening in Node.js and why it matters&lt;/h2&gt;
&lt;p&gt;Since we’re talking about the book, let me share some thoughts on where Node.js is heading. This context helps explain some of the choices we made in the fourth edition.&lt;/p&gt;
&lt;h3 id=&quot;nodejs-24-lts-and-beyond&quot;&gt;Node.js 24 LTS and beyond&lt;/h3&gt;
&lt;p&gt;Node.js 24 LTS isn’t about one killer feature. It’s about a lot of small, practical upgrades that add up to cleaner, safer, faster applications. The theme is modern JavaScript, better defaults, and a stronger security posture.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;permission model&lt;/strong&gt; continues to mature. It lets you restrict file system access, network access, child processes, and more. Node.js is moving closer to “secure by default,” which is especially useful for CLIs, CI environments, multi-tenant systems, or anything that runs untrusted code.&lt;/p&gt;
&lt;p&gt;What this means for you as a developer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write cleaner JavaScript with fewer hacks&lt;/li&gt;
&lt;li&gt;Get better performance mostly “for free” from V8 improvements&lt;/li&gt;
&lt;li&gt;Ship safer code by locking down what your process can touch&lt;/li&gt;
&lt;li&gt;Rely more on Node’s built-ins (tests, HTTP, routing) instead of gluing many small libraries together&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;is-nodejs-losing-popularity&quot;&gt;Is Node.js losing popularity?&lt;/h3&gt;
&lt;p&gt;There’s ongoing chatter that Node.js has cooled down compared to the 2015–2020 boom. Let me give you an honest take.&lt;/p&gt;
&lt;p&gt;Competition from Bun, Deno, and Cloudflare Workers has actually been &lt;strong&gt;good&lt;/strong&gt; for Node.js. It fostered a new wave of development after a phase of relative stagnation. This competition has pushed Node.js toward:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;More focus on performance and security&lt;/li&gt;
&lt;li&gt;Better integration with TypeScript&lt;/li&gt;
&lt;li&gt;Improved compatibility with web standards&lt;/li&gt;
&lt;li&gt;A revamped website and improved documentation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But Node.js has significant advantages that I don’t see going away:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It’s truly open&lt;/strong&gt;. Not just open source, but open governance. There isn’t a VC-backed company behind it (unlike Deno, Bun, or Cloudflare Workers). It’s a community supported by the Linux Foundation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It has a long history and wide adoption&lt;/strong&gt;. This gives it access to the largest ecosystem of packages and the most battle-tested production deployments. That’s why all the competitors are seeking to claim Node.js compatibility: they see it as a necessary feature to stay relevant in the market.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is why I believe Node.js isn’t in danger. As long as the community keeps thriving and Node.js keeps evolving based on market needs, it will continue growing and succeeding.&lt;/p&gt;
&lt;p&gt;If nothing else, Node.js seems to have reached an important maturity stage where it can safely be considered a solid foundation even for the most ambitious enterprise projects. This is only going to help consolidate Node.js’s current position in the market and hopefully foster a new wave of innovation and growth.&lt;/p&gt;
&lt;p&gt;Looking ahead, Node.js is also uniquely positioned for an emerging category of applications: &lt;strong&gt;AI agents&lt;/strong&gt;. Building AI-powered systems requires handling concurrent API calls, streaming responses from language models, and orchestrating complex workflows. Node.js’s native support for async operations, its mature streaming primitives, and its massive ecosystem of packages make it an excellent choice for this new wave of development. If you’re exploring AI agents or agentic workflows, you’ll find that the patterns in this book transfer directly to that domain.&lt;/p&gt;
&lt;h3 id=&quot;the-biggest-challenges-nodejs-developers-face-today&quot;&gt;The biggest challenges Node.js developers face today&lt;/h3&gt;
&lt;p&gt;Across consulting work and conversations with the community, I see the same pain points coming up repeatedly:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Truly understanding the async model.&lt;/strong&gt; Many developers use async/await without really understanding how the event loop and task queues work, or what actually runs in parallel versus what is just “nicely indented.” The result? Blocking the event loop with CPU-heavy work, or assuming &lt;code&gt;await&lt;/code&gt; makes things concurrent.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Architecting large applications.&lt;/strong&gt; Starting a small Node.js app is easy; growing it sanely is hard. Common problems include spaghetti modules, no clear layers, god objects, and global state everywhere. Some teams split into microservices too early and just add distributed complexity. Others never split and end up with an unmanageable monolith.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Managing async complexity.&lt;/strong&gt; Async/await solved readability, but not concurrency strategy. People still do sequential &lt;code&gt;await&lt;/code&gt; where they could run tasks in parallel with &lt;code&gt;Promise.all&lt;/code&gt; or &lt;code&gt;Promise.allSettled&lt;/code&gt;. Streams remain underused, and many developers still load entire files or payloads into memory.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dependency management and security.&lt;/strong&gt; npm’s richness is a double-edged sword. Huge trees of transitive dependencies, constant updates, occasional supply-chain attacks. You need a strategy for dependencies: auditing, updating, and being intentional about what you pull in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Testing culture.&lt;/strong&gt; Many Node.js codebases still lack solid tests, especially on the backend. The tools are good now (built-in test runner, Jest, etc.), but habits lag behind.&lt;/p&gt;
&lt;h3 id=&quot;if-i-could-fix-one-misconception&quot;&gt;If I could fix one misconception&lt;/h3&gt;
&lt;p&gt;If I could magically fix one thing in every Node.js developer’s head, it would be the mental model around &lt;strong&gt;concurrency and the event loop&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Node.js is single-threaded for JavaScript, but not single-tasked. Your job is to keep the event loop free, avoid heavy synchronous work, and use the right tools (async I/O, worker threads, queues) for concurrency and parallelism.&lt;/p&gt;
&lt;p&gt;If every Node.js developer truly understood “don’t block the event loop, design around it,” a huge class of performance and scalability issues would simply disappear. And Node.js would truly be leveraged in all its power.&lt;/p&gt;
&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Here’s my key message: &lt;strong&gt;Node.js is still one of the best bets for building full-stack applications&lt;/strong&gt;, whether you’re building traditional web services, real-time systems, or the next generation of AI-powered tools. It’s worth investing in learning it deeply.&lt;/p&gt;
&lt;p&gt;The fourth edition of Node.js Design Patterns is our attempt to give you everything you need to go from writing Node.js code to designing and shipping production-grade systems with confidence. Whether you’re looking to level up your skills, onboard a team, or simply have a comprehensive reference on your desk, we hope this book serves you well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Get the book:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejsdp.link/buy&quot;&gt;Amazon (Print)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejsdp.link/buy-kindle&quot;&gt;Amazon (Kindle)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.packtpub.com/en-us/product/nodejs-design-patterns-9781803235431&quot;&gt;Packt Publishing (multiple formats)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;More resources:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejsdesignpatterns.com/&quot;&gt;Official website&lt;/a&gt; (including the free Streams chapter)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/PacktPublishing/Node.js-Design-Patterns-fourth-Edition&quot;&gt;Code examples on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have questions, want to share your thoughts, or just want to say hi, feel free to leave a comment below or reach out on &lt;a href=&quot;https://bsky.app/profile/loige.co&quot;&gt;Bluesky&lt;/a&gt;. I’d love to hear from you, especially if you end up reading the book and it helps you on your Node.js journey.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/nodejs-design-patterns-fourth-edition.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/nodejs-design-patterns-fourth-edition.png" width="1200" height="630"/></media:content><category>node-js</category><category>javascript</category><category>books</category><author>Luciano Mammino</author><comments>https://loige.co/nodejs-design-patterns-fourth-edition/#comments</comments><enclosure url="https://loige.co/og/nodejs-design-patterns-fourth-edition.png" length="0" type="image/png"/></item><item><title>Farewell FullStack Bulletin</title><link>https://loige.co/farewell-fullstack-bulletin/</link><guid isPermaLink="true">https://loige.co/farewell-fullstack-bulletin/</guid><description>After 458 issues, 3,073+ curated links, and nearly a decade of weekly curation, FullStack Bulletin is closing. Here&apos;s the story of the journey, why it&apos;s ending, and what lives on.</description><pubDate>Sun, 29 Mar 2026 12:15:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;There is no real ending. It’s just the place where you stop the story.&lt;br&gt;
― Frank Herbert&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After 458 issues, 3,073+ curated links, and almost nine years of showing up in your inbox every week, &lt;a href=&quot;https://andreamangano.com/&quot;&gt;Andrea&lt;/a&gt; and I have decided to close &lt;a href=&quot;https://fullstackbulletin.com&quot;&gt;FullStack Bulletin&lt;/a&gt; (the newsletter). For real this time…&lt;/p&gt;
&lt;p&gt;If you’ve been following along, you might remember that just over a year ago I wrote &lt;a href=&quot;/404-newsletter-found/&quot;&gt;404: Newsletter Found&lt;/a&gt;, a celebratory post where I reflected on the journey and committed to giving FullStack Bulletin &lt;em&gt;one more shot&lt;/em&gt;. I meant every word of it. We both did. We pushed through 2025, reached 450 issues, moved to Buttondown, kept innovating and kept curating week after week with the same care we always had.&lt;/p&gt;
&lt;p&gt;But sometimes giving something your best shot is exactly what helps you realize it’s time to let go.&lt;/p&gt;
&lt;p&gt;This isn’t an obituary. It’s a love letter.&lt;/p&gt;
&lt;p&gt;So pour yourself a coffee (or a beer, depending on your timezone and your coping mechanisms), and let me tell you the story of a newsletter that started as a weekend experiment between two friends and somehow became a nine-year journey through the ever-changing landscape of full-stack web development.&lt;/p&gt;
&lt;h2 id=&quot;what-fullstack-bulletin-was&quot;&gt;What FullStack Bulletin was&lt;/h2&gt;
&lt;p&gt;For those who never had the pleasure: FullStack Bulletin was a free weekly newsletter for full-stack web developers. Every issue contained seven hand-selected articles from across the web (plus a few extra ones at the bottom), one book recommendation, and one inspirational tech quote. No fluff, no spam, no algorithmic feed. Just two humans reading and being inspired by a lot of stuff on the internet and wanting to share the learnings with 3,000+ developers around the world.&lt;/p&gt;
&lt;p&gt;I started the project in March 2017 together with my dear friend and former colleague &lt;a href=&quot;https://andreamangano.com/&quot;&gt;Andrea Mangano&lt;/a&gt;. We originally designed the format together. Andrea is responsible for the iconic look and feel that defined FullStack Bulletin from day one: the bold yellow branding, the clean layout, the sense that someone actually cared about the reading experience. I took care of the technical side: the automation pipeline, the infrastructure, and most of the weekly curation.&lt;/p&gt;
&lt;p&gt;FullStack Bulletin was the newsletter we wished we had when we started our own careers. The full-stack world moves fast, impossibly fast, and keeping up with everything from frontend frameworks to database internals to deployment strategies can feel like drinking from a firehose. We wanted to be the filter. Every Monday, you’d open your inbox and find a small, curated window into the best of what the web development world had produced that week. And if it wasn’t the absolute best, it was at least our take on something that could teach you something new, challenge your assumptions, or simply make you smile and remind you why we love this craft so much.&lt;/p&gt;
&lt;p&gt;In fact, what made it special, I think, wasn’t the content itself. You could find great articles anywhere. What made it special was the human touch: two people who genuinely loved this craft, spending their evenings and weekends reading, discussing, ranking, and assembling something they were proud to send. In an age of algorithmic recommendations and AI-generated summaries, there was something stubbornly beautiful about that. Even when we threw in an off-topic gem every once in a while, it’s because that content had given us something we could bring back to our own work. We wanted to share that with our readers, and we hoped it would spark a similar sense of discovery and delight.&lt;/p&gt;
&lt;p&gt;If you want the full origin story, I told it in detail in &lt;a href=&quot;/404-newsletter-found/&quot;&gt;404: Newsletter Found&lt;/a&gt;. That post also digs into the technical architecture behind the automation, the static APIs for books and quotes, and the Step Function pipeline that kept the whole thing running on AWS for a long while.&lt;/p&gt;
&lt;h2 id=&quot;458-issues-and-counting-well-not-anymore&quot;&gt;458 issues and counting (well, not anymore)&lt;/h2&gt;
&lt;p&gt;Let me put some numbers on this, because they still blow my mind.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;458 issues&lt;/strong&gt; published&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3,073+ links&lt;/strong&gt; shared&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;~9 years&lt;/strong&gt; of weekly curation (March 2017 to March 2026)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3,000+ subscribers&lt;/strong&gt; at our peak&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s nearly nine years of Mondays. Nine years of reading dozens of articles every week, picking the best seven, writing an editorial intro, selecting a book and a quote, and hitting send. Multiply that by the number of evenings and weekends it took, and you start to get a sense of what this project asked of us. Just thinking back, this is probably the longest sustained creative project I’ve ever been part of. Probably the most consistent thing I’ve done in my entire life, tech or otherwise! And it was a labor of love every step of the way.&lt;/p&gt;
&lt;p&gt;The early days were pure adrenaline. The first issue went out to a handful of friends and colleagues, and every new subscriber felt like a small miracle. Andrea and I would text each other whenever someone signed up. &lt;em&gt;“We got another one!”&lt;/em&gt; We were building something from nothing, and the excitement of it made the work feel effortless, as it often happens with many side projects…&lt;/p&gt;
&lt;p&gt;Then came the automation. I’ve always had a tendency to automate things (some would say too much), and FullStack Bulletin became my favorite playground. What started as a fully manual process gradually evolved into a sophisticated pipeline: an AWS Step Function that scraped links from our socials (Twitter first, then Mastodon once it became X), fetched titles and descriptions, ranked content, pulled in the book and quote of the week from our static APIs on GitHub, and assembled a draft issue ready for review.&lt;/p&gt;
&lt;p&gt;The content selection always remained manual (who would want a soulless, overly mechanical newsletter?). But the automation handled the heavy lifting and freed us to focus on what mattered most: the curation itself. We still spent lots of time trying to make every issue tell a story, tying the links together and explaining why we cared about them and how we bumped into them in our busy developer lives.&lt;/p&gt;
&lt;p&gt;Some of the most fun I had with the project was during the live refactoring sessions with my friend &lt;a href=&quot;https://www.gambuzzi.it/&quot;&gt;Roberto Gambuzzi&lt;/a&gt;. We streamed on &lt;a href=&quot;https://www.twitch.tv/loige&quot;&gt;Twitch&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/@loige&quot;&gt;YouTube&lt;/a&gt;, splitting the original monolithic Lambda function into a proper Step Function and rewriting pieces of it in Rust. Raw, unscripted, full of real-world problem-solving. If you’re curious, &lt;a href=&quot;https://www.youtube.com/playlist?list=PLbNOKnE-Oyr1tsUft4j0QZDyk5iFcVVy_&quot;&gt;the full playlist is still up&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In 2025, we migrated from Mailchimp to &lt;a href=&quot;https://buttondown.com/fullstackbulletin/archive/&quot;&gt;Buttondown&lt;/a&gt;, which gave us a cleaner publishing experience and a better archive (at less than half the cost). We hit the 450-issue mark and I remember thinking: &lt;em&gt;500 is within reach. Just another year.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Along the way, we were fortunate to collaborate with incredible sponsors who believed in what we were doing: &lt;em&gt;PostHog&lt;/em&gt;, &lt;em&gt;Dashlane&lt;/em&gt;, &lt;em&gt;Buttonize&lt;/em&gt;, &lt;em&gt;Packt&lt;/em&gt;, &lt;em&gt;Belka&lt;/em&gt;, &lt;em&gt;MisterDA&lt;/em&gt;, &lt;em&gt;ConfigCat&lt;/em&gt;, &lt;em&gt;FeedHive&lt;/em&gt;, &lt;em&gt;Upstash&lt;/em&gt;, &lt;em&gt;Nudge&lt;/em&gt;, and &lt;em&gt;Trigger.dev&lt;/em&gt;. Even if we were never profitable, their support helped us a bunch to keep the lights on and I am genuinely grateful for every one of them. We were never about clickthrough volumes so these sponsors always bought into our vision and never once asked us to compromise on what we curated. That trust meant the world.&lt;/p&gt;
&lt;p&gt;And then there were 458 weekends where we showed up, even when we were tired, even when life got in the way, even when the easy thing would have been to skip a week. Consistency isn’t glamorous, but there’s a quiet kind of pride in it. We did that. For almost a decade.&lt;/p&gt;
&lt;h2 id=&quot;why-were-stopping&quot;&gt;Why we’re stopping&lt;/h2&gt;
&lt;p&gt;Here’s the part where I have to be honest with you. And with myself.&lt;/p&gt;
&lt;p&gt;In December 2024, I wrote in the &lt;a href=&quot;/404-newsletter-found/&quot;&gt;404: Newsletter Found&lt;/a&gt; post:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[…] instead of stepping away, I’ve decided to give FullStack Bulletin one more shot. I believe in its value and the role it plays in the full-stack developer community. My goal for the coming year is to grow the number of subscribers and secure more long-term sponsorships to make the project sustainable. With a larger audience and reliable sponsorship, I could reduce the financial strain and even consider bringing on someone to help with the workload.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I meant it. And in some ways, 2025 was a good year for the newsletter. We stayed consistent, reached 450 issues, changed the tone and the structure, spent even more time each week on the storytelling… and engagement actually improved quite a bit!&lt;/p&gt;
&lt;p&gt;But the growth in subscribers didn’t materialize. The sponsorships we secured were fantastic, but not enough to make the project financially sustainable. And the workload? It kept growing, not because of the newsletter itself, but because of everything else in our lives.&lt;/p&gt;
&lt;p&gt;Plus, life has a way of shifting priorities when you’re not looking…&lt;/p&gt;
&lt;p&gt;Our families grew. Our work responsibilities deepened. I kept picking up new passions and side projects: writing &lt;a href=&quot;/nodejs-design-patterns-fourth-edition/&quot;&gt;the fourth edition of Node.js Design Patterns&lt;/a&gt;, working on the &lt;a href=&quot;https://rust-lambda.com&quot;&gt;Rust and Lambda book&lt;/a&gt;, speaking at conferences, training for BJJ and staying in shape, trying to be a present father and partner. Andrea had his own evolving world of commitments and ambitions. The hours in a day didn’t change, but the number of things competing for them kept growing.&lt;/p&gt;
&lt;p&gt;And here’s the thing about curation: it only works if you do it well. A half-hearted newsletter is worse than no newsletter at all. Every week, I could feel the tension between the quality I wanted to deliver and the time I actually had. Some weeks I managed to bridge that gap. Others, I barely squeezed through. The joy of the process, the thing that had kept us going for years, started to feel more like obligation. Yet, I kept doing it for a while, because when you have done something for so long, it always feels you are on the verge of a breakthrough and everything will become easier after that. You just need one more rep.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Cartoon of two miners digging through rock toward a wall of blue diamonds. The miner in the lower tunnel turns back and walks away just before reaching the gems, while the miner above keeps digging. The image symbolizes perseverance and the fear of giving up right before a breakthrough.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1450&quot; height=&quot;1178&quot; src=&quot;https://loige.co/_astro/never-give-up.B_fwE0Tb_Z1NgCqW.webp&quot; &gt;&lt;/p&gt;
&lt;small&gt;
&lt;p&gt;The hardest part of any long effort: you can never quite tell whether you are wisely persevering or simply refusing to admit it is time to stop. &lt;a href=&quot;https://en.wikipedia.org/wiki/Sunk_cost#Fallacy_effect&quot;&gt;Sunk cost fallacy&lt;/a&gt; at its finest.&lt;/p&gt;
&lt;/small&gt;
&lt;p&gt;And then, a few weeks ago, it hit me. One of those rare moments of clarity where the fog lifts and you see the thing for what it really is. The newsletter had become more of a source of stress than a source of joy. The tension between what I wanted to deliver and what I could actually deliver was no longer sustainable. The project that had once been a labor of love was starting to feel like a burden. And if we kept going, we risked something far worse than stopping: we might end up resenting something we had built with so much care and passion.&lt;/p&gt;
&lt;p&gt;Once I said it out loud, the decision was obvious. I called Andrea, and it turned out he had been feeling the same way. We didn’t need to convince each other. We just needed to admit it to each other.&lt;/p&gt;
&lt;p&gt;So that’s what we’re doing. No regrets. Just acceptance that this chapter has reached its final page.&lt;/p&gt;
&lt;h2 id=&quot;what-lives-on&quot;&gt;What lives on&lt;/h2&gt;
&lt;p&gt;Closing the newsletter doesn’t mean erasing it. One thing Andrea and I agreed on from the start of this conversation was that we wanted to leave the door open for anyone who might want to revisit what we built, learn from it, or even build on top of it. Everything is still out there, and we intend to keep it that way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The archive is fully preserved.&lt;/strong&gt; All 458 issues are searchable and browsable at &lt;a href=&quot;https://fullstackbulletin.com&quot;&gt;fullstackbulletin.com&lt;/a&gt;. If you want to take a trip down memory lane, rediscover the trends that shaped web development over the years, or simply find a gem you missed, it’s all there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The data is also yours to explore.&lt;/strong&gt; We’ve made the entire archive available as structured data: &lt;a href=&quot;https://fullstackbulletin.com/fullstackbulletin-archive.json&quot;&gt;JSON&lt;/a&gt; and &lt;a href=&quot;https://fullstackbulletin.com/fullstackbulletin-archive.parquet&quot;&gt;Parquet&lt;/a&gt; files that you can download and query. You could even load the Parquet file into &lt;a href=&quot;https://duckdb.org&quot;&gt;DuckDB&lt;/a&gt; and run SQL queries against almost a decade of full-stack web development trends. Because if we’re going to close a newsletter, we’re going to do it the nerd way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The code is open source.&lt;/strong&gt; Everything that powered FullStack Bulletin lives on GitHub:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FullStackBulletin/automation&quot;&gt;FullStackBulletin/automation&lt;/a&gt; — the Step Function pipeline that scraped, ranked, and published every issue&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FullStackBulletin/tech-quotes&quot;&gt;FullStackBulletin/tech-quotes&lt;/a&gt; — a curated collection of inspirational tech quotes (one shipped with every issue)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FullStackBulletin/fullstack-books&quot;&gt;FullStackBulletin/fullstack-books&lt;/a&gt; — a hand-picked list of books for full-stack developers&lt;/li&gt;
&lt;li&gt;Even the full website code that powers &lt;a href=&quot;https://github.com/FullStackBulletin/fullstackbulletin.com&quot;&gt;fullstackbulletin.com is open source&lt;/a&gt;!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you ever want to start your own newsletter project, this code might be a useful starting point. Fork it, adapt it, make it your own. After all, that’s what open source is for and we truly believe in it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The live coding sessions are still up.&lt;/strong&gt; The &lt;a href=&quot;https://www.youtube.com/playlist?list=PLbNOKnE-Oyr1tsUft4j0QZDyk5iFcVVy_&quot;&gt;YouTube playlist&lt;/a&gt; of our refactoring sessions with Roberto Gambuzzi is there for anyone who enjoys watching two developers &lt;del&gt;argue&lt;/del&gt; debate about Rust lifetimes while debugging a Lambda function at 7pm on a Monday.&lt;/p&gt;
&lt;p&gt;And if you’re looking for newsletters and creators to fill the FullStack Bulletin-shaped hole in your inbox, we’ve curated a list of our favorites on the &lt;a href=&quot;https://fullstackbulletin.com&quot;&gt;official farewell page&lt;/a&gt;. There’s even an &lt;a href=&quot;https://fullstackbulletin.com/fullstackbulletin-recommended-feeds.opml&quot;&gt;&lt;strong&gt;OPML&lt;/strong&gt; file&lt;/a&gt; you can import into your favourite &lt;strong&gt;RSS reader&lt;/strong&gt; for a unified stream of full-stack inspiration. Because old habits die hard. It won’t replace FullStack Bulletin, but it will surely give you tons of insights and inspirations to keep up with the ever-evolving world of web development.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Screenshot of a desktop RSS reader showing the curated FullStack Bulletin OPML feed. The left sidebar lists blogs and writers included in the collection, the middle column shows recent posts from Marvin Hagemeister, and the main reading pane displays his article “Signals vs Query-Based Compilers.” The image highlights the newsletter’s inspiration sources and the kind of technical writing behind its curation.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2958&quot; height=&quot;1824&quot; src=&quot;https://loige.co/_astro/fullstack-bulletin-curated-opml-rss-feed.B7hrm1DJ_Z2fejwB.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Load the OPML file into your favourite RSS reader and you’ll have a direct window into the ecosystem that fed FullStack Bulletin for years.&lt;/small&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-fullstack-bulletin-could-have-been&quot;&gt;What FullStack Bulletin could have been&lt;/h2&gt;
&lt;p&gt;This is the section I’ve been putting off writing.&lt;/p&gt;
&lt;p&gt;I’m not bitter. But there’s a particular kind of ache that comes with closing something you built with someone you care about, and letting yourself imagine what it could have become.&lt;/p&gt;
&lt;p&gt;Life pulled Andrea and me in a hundred different directions over the years, but every Monday, FullStack Bulletin was a reason to stay connected. A shared project, a shared routine, a thread running through the chaos of two lives lived in parallel. That kind of sustained creative partnership is rare. Most side projects die within a few months. Most collaborations dissolve when life gets complicated. Ours lasted almost a decade, and it only ended because we chose to end it together, not because it fell apart.&lt;/p&gt;
&lt;p&gt;And we weren’t short on ideas. If anything, we had too many of them.&lt;/p&gt;
&lt;p&gt;One of the things I’m proudest of is how much the newsletter’s voice evolved. We went from a straightforward list of links to something with real editorial personality: every issue told a small story, connecting the articles, giving you context for why we picked them. I think we got pretty good at that. But there was so much more room to explore: deeper commentary, themed issues, maybe even guest curators bringing fresh perspectives from corners of the stack we didn’t cover as well.&lt;/p&gt;
&lt;p&gt;And then there was Andrea’s redesign. He had been working on a completely new visual identity for FullStack Bulletin, a bold rethink of the look and feel that I genuinely believe would have been a game changer. It never shipped, but I think it’s only fair to Andrea to let you see a glimpse of what a newly revamped FullStack Bulletin could have looked like:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Brand concept board for FullStack Bulletin in a pixel art style. It shows several logo variations with a pixel crown icon, a mock landing page on a dark purple background, a set of playing cards featuring a unicorn wearing a VR headset, a mint and purple alternate logo treatment, a three color palette with mint, pale yellow, and dark purple swatches, and a larger close up of the pixel unicorn illustration.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1106&quot; height=&quot;1966&quot; src=&quot;https://loige.co/_astro/fsb-redesign.TnNetk2z_CcvnC.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Modern, old school, and unapologetically nerdy at the same time. I genuinely love it.&lt;/small&gt;&lt;/p&gt;
&lt;h2 id=&quot;so-long-and-thanks-for-all-the-links&quot;&gt;So long, and thanks for all the links&lt;/h2&gt;
&lt;p&gt;First, I want to thank &lt;a href=&quot;https://andreamangano.com/&quot;&gt;Andrea&lt;/a&gt;. We dreamed this thing up together, built it together, and carried it together for almost a decade. You brought the eye for design, the calm when I was overthinking, and the friendship that made the work feel less like work. FullStack Bulletin wouldn’t have been FullStack Bulletin without you. I’m grateful beyond words.&lt;/p&gt;
&lt;p&gt;Thank you to every sponsor who believed in what we were doing: &lt;em&gt;PostHog&lt;/em&gt;, &lt;em&gt;Dashlane&lt;/em&gt;, &lt;em&gt;Buttonize&lt;/em&gt;, &lt;em&gt;Packt&lt;/em&gt;, &lt;em&gt;Belka&lt;/em&gt;, &lt;em&gt;MisterDA&lt;/em&gt;, &lt;em&gt;ConfigCat&lt;/em&gt;, &lt;em&gt;FeedHive&lt;/em&gt;, &lt;em&gt;Upstash&lt;/em&gt;, &lt;em&gt;Nudge&lt;/em&gt;, and &lt;em&gt;Trigger.dev&lt;/em&gt;. You kept the lights on and you never once asked us to compromise on what we curated. That trust meant the world.&lt;/p&gt;
&lt;p&gt;Thank you to &lt;a href=&quot;https://www.gambuzzi.it/&quot;&gt;Roberto Gambuzzi&lt;/a&gt; for the late-night live coding sessions that turned infrastructure refactoring into entertainment. Those streams were some of the most fun I’ve had as a developer.&lt;/p&gt;
&lt;p&gt;Thank you to every author, blogger, and creator whose work we curated over the years. FullStack Bulletin existed because the web development community produces incredible content, generously and most often for free. You are the real heroes here.&lt;/p&gt;
&lt;p&gt;And thank you. Yes, you. The subscriber who opened our emails every Monday. The one who clicked through the links, tried the tools, read the books, and occasionally hit reply to tell us you enjoyed the issue. Maybe you’ve been with us since Issue #1, or maybe you found us somewhere along the way. Either way, you are the reason we kept going for 458 Mondays. Connecting with you, even through something as simple as a weekly email, has been one of the most rewarding experiences of my life.&lt;/p&gt;
&lt;p&gt;FullStack Bulletin taught me that community is built one email at a time. That consistency compounds. That curating someone else’s brilliance is its own form of creativity. And that the best projects are the ones you build with people you love.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I may not have gone where I intended to go, but I think I have ended up where I needed to be.&lt;br&gt;
— Douglas Adams&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In my &lt;a href=&quot;/404-newsletter-found/&quot;&gt;404: Newsletter Found&lt;/a&gt; post, I closed with: &lt;em&gt;“Here’s to Issue 404… and beyond!”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Well, we went beyond. Fifty-four issues beyond, to be exact.&lt;/p&gt;
&lt;p&gt;And there will be one more. Issue #459, the very last one, will land in your inbox soon to close the loop and point you right here. Consider it our final Monday together.&lt;/p&gt;
&lt;p&gt;OK, that sounded a bit overdramatic, didn’t it? Don’t worry, I’m not going anywhere. I’ll still be around with all my other projects and the same passion for sharing knowledge and connecting with people who care about this craft. FullStack Bulletin was one chapter, but the story continues in other forms. If you want to stay in touch, all my social links are in the footer of this blog. Don’t hesitate to connect and reach out.&lt;/p&gt;
&lt;p&gt;Here’s to Issue #459. And what a ride it’s been!&lt;/p&gt;
&lt;p&gt;Thank you for reading. Thank you for subscribing. Thank you for being part of this. ❤️&lt;/p&gt;
&lt;p&gt;So long, and thanks for all the links.&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/farewell-fullstack-bulletin.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/farewell-fullstack-bulletin.png" width="1200" height="630"/></media:content><category>life</category><category>collaboration</category><author>Luciano Mammino</author><comments>https://loige.co/farewell-fullstack-bulletin/#comments</comments><enclosure url="https://loige.co/og/farewell-fullstack-bulletin.png" length="0" type="image/png"/></item><item><title>2025 - A year in Review</title><link>https://loige.co/2025-a-year-in-review/</link><guid isPermaLink="true">https://loige.co/2025-a-year-in-review/</guid><description>Luciano Mammino&apos;s 2025 year in review: releasing the fourth edition of Node.js Design Patterns, progressing on Crafting Lambda Functions in Rust, approaching 5 years at FourTheorem, public speaking, AWS Bites podcast, open source contributions, and some major personal milestones.</description><pubDate>Tue, 30 Dec 2025 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;2025: That’s a wrap! 🌯&lt;/p&gt;
&lt;p&gt;Another lap around the sun completed and, as (my very own) tradition dictates, it’s time for yet another self-indulgent review of all the things I have (and maybe I haven’t) accomplished professionally and personally in 2025.&lt;/p&gt;
&lt;p&gt;The usual disclaimer applies: I write these posts mostly for myself. They are my own time capsule, a way to look back and reflect on what I’ve done and where I’m going. If you’ve stumbled upon this post and you’re brave enough to read through it, I hope you’re armed with a steaming cup of coffee (or hot chocolate, I don’t judge) to keep you warm and awake through these cold winter days. You’ll need it!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Close-up of a man covered in frost and snow, staring blankly in a wintry scene—an exaggerated &amp;amp;#x27;end of year&amp;amp;#x27; mood.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;417&quot; height=&quot;267&quot; src=&quot;https://loige.co/_astro/boring-cold.Xfo5opWZ_15dzc1.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;P.S. If you need an incentive to power through: this year brought a &lt;em&gt;personal&lt;/em&gt; unexpected surprise that might just make it the best year ever for me. But no spoilers… you’ll have to read all the way to the end to find out!&lt;/p&gt;
&lt;h2 id=&quot;hitting-the-shelves-with-nodejs-design-patterns-4th-edition&quot;&gt;Hitting the shelves with Node.js Design Patterns 4th edition&lt;/h2&gt;
&lt;p&gt;Let’s start with what has probably been one of the biggest highlights of my year: the release of the &lt;strong&gt;fourth edition&lt;/strong&gt; of &lt;em&gt;Node.js Design Patterns&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nodejsdesignpatterns.com/&quot;&gt;Node.js Design Patterns&lt;/a&gt; is a book I co-authored with the amazing &lt;a href=&quot;https://twitter.com/mariocasciaro&quot;&gt;Mario Casciaro&lt;/a&gt;. It’s a comprehensive guide that takes you from the fundamentals of Node.js all the way to advanced design patterns for building scalable and production-ready applications.&lt;/p&gt;
&lt;p&gt;This year marks a huge milestone: after 5 years since the third edition, we released the &lt;strong&gt;fourth edition&lt;/strong&gt; on September 25, 2025!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A person sitting on a couch, holding and reading the book ‘Node.js Design Patterns (Fourth Edition)’&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;666&quot; src=&quot;https://loige.co/_astro/person-holding-nodejs-design-patterns-fourth-edition.CUwiIBUI_Z1uztEN.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;This new edition is fully updated for &lt;strong&gt;Node.js 24&lt;/strong&gt; and features modern JavaScript throughout, with ECMAScript modules and async/await as the default patterns. The biggest addition is &lt;strong&gt;Chapter 10&lt;/strong&gt;, an entirely new chapter dedicated to testing patterns and best practices, reflecting the fact that Node.js’s built-in test runner has become a first-class citizen. We also had to make some tough choices: the Universal (isomorphic) JavaScript chapter was removed since tools like React and Next.js have reshaped how that topic is approached, and well… the book was already pushing 700+ pages!&lt;/p&gt;
&lt;p&gt;Speaking of pages, here’s a fun fact: at some point during the writing process, we realized with the publisher that we had exceeded the maximum number of pages allowed by Amazon’s print-on-demand system. We literally had to cut down some content to make it fit!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The book ‘Node.js Design Patterns (Fourth Edition)’ lying on a digital kitchen scale showing 1.38 kg&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;624&quot; src=&quot;https://loige.co/_astro/nodejs-desgin-patterns-book-fourth-edition-on-a-scale.DcDy1YeW_25V4SS.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Yes, the picture above shows the book on a scale, weighing in at a hefty &lt;strong&gt;1.38 kg&lt;/strong&gt; (about 3 pounds for those of you who like non-standard units 🙃)! Definitely not a light read, but hey, knowledge comes at a weight! And if you’re in trouble you can always use it to defend yourself! 🙈&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;Jokes aside, this edition also marks a personal milestone for me. Mario was incredibly kind and gave me the spotlight by putting my name first on the cover for the very first time. If you’ve read &lt;a href=&quot;/nodejs-design-patterns-fourth-edition&quot;&gt;the story of how I came to work on this book&lt;/a&gt;, you’ll understand why this is such an honor and a meaningful milestone for me as an author.&lt;/p&gt;
&lt;p&gt;Producing this new edition was quite intense: for the majority of the second half of 2025, this book was my main focus outside of work. Countless evenings and weekends went into reviewing, rewriting, and polishing every chapter. But seeing the final result makes it all worth it.&lt;/p&gt;
&lt;p&gt;If you want to know all the details about what’s new in this edition, check out &lt;a href=&quot;/nodejs-design-patterns-fourth-edition&quot;&gt;the dedicated announcement post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;… And if you’ll have a chance to read it, make sure to leave us a review on Amazon or Goodreads. Reviews really help authors like us reach more readers! Probably the biggest gift you can give us, especially if you enjoyed the book!&lt;/p&gt;
&lt;p&gt;I’m not sure how much time I’ll have for the book in 2026, but there’s certainly some promotion work to do and I have a list of blog articles I want to write to complement the book’s content. Stay tuned on the &lt;a href=&quot;https://nodejsdesignpatterns.com/blog&quot;&gt;Node.js Design Patterns blog&lt;/a&gt;!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A mind needs books as a sword needs a whetstone, if it is to keep its edge.&lt;br&gt;
— Tyrion Lannister&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;making-progress-on-crafting-lambda-functions-in-rust&quot;&gt;Making progress on Crafting Lambda Functions in Rust&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://rust-lambda.com/&quot;&gt;Crafting Lambda Functions in Rust&lt;/a&gt; is a book I am co-authoring with the brilliant &lt;a href=&quot;https://jameseastham.co.uk/&quot;&gt;James Eastham&lt;/a&gt;. It’s a hands-on guide that teaches you how to build serverless applications on AWS using Rust, from the basics all the way to production-ready patterns. This one is a &lt;strong&gt;self-published&lt;/strong&gt; project and while it’s still a work in progress, it’s already available as &lt;strong&gt;early access&lt;/strong&gt; at a discounted price. The deal is simple: you get everything that’s available now for a lower price, and any future updates are free. It’s a sneak peek into the content as it develops, and a way to support the project too!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;3D mockup of the book cover ‘Crafting Lambda Functions in Rust’ against a colorful confetti-style background, with a small crab mascot on the cover&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;535&quot; src=&quot;https://loige.co/_astro/crafting-lambda-functions-in-rust-with-festive-bg.CSwwNZgF_Z3Hhcs.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;I have to be honest: working on two books at the same time was &lt;em&gt;tough&lt;/em&gt;. Probably the thing I struggled the most with during the year. As always, I underestimated both the amount of free time I would have and the effort needed to write content, especially when it’s new content on novel topics where the research required is non-trivial. But if there’s one thing that has been holding true throughout my career is that we, software developers, are always pretty optimistic when it comes to estimating time and effort! Will we ever learn? Probably not…&lt;/p&gt;
&lt;p&gt;But back to the book(s)… At some point, it became overwhelming to juggle both projects, and I had to almost pause this book to focus on Node.js Design Patterns. A huge thanks goes to James for being so understanding and flexible with the timelines, and for taking care of the book while I was buried in Node.js patterns! Also thanks to all the current early-access readers for understanding my position and being patient with the slower pace of releases.&lt;/p&gt;
&lt;p&gt;Despite the time constraints, we still managed to ship &lt;strong&gt;3 solid releases&lt;/strong&gt; throughout the year:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Release 1&lt;/strong&gt; focused on polish and modernisation: we squashed a ton of typos and inconsistencies (big shout-out to David Behroozi, Darko Mesaroš, and Gary Sassano for their sharp-eyed feedback!), updated all code examples to align with the new &lt;code&gt;cargo-lambda&lt;/code&gt; project structure, and added a brand new &lt;strong&gt;CDK deployment appendix&lt;/strong&gt; for those who prefer CDK over SAM.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Release 2&lt;/strong&gt; brought &lt;strong&gt;Chapter 7: Configuration&lt;/strong&gt;. This chapter dives deep into the art of passing parameters to your Lambda functions: from environment variables to cleanly separating configuration from code, all the way to securely managing secrets with AWS Systems Manager Parameter Store and AWS Secrets Manager. We also added a &lt;strong&gt;Terraform appendix&lt;/strong&gt; for those who prefer Terraform over SAM or CDK for deploying their Rust Lambda functions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Release 3&lt;/strong&gt; was the big one: &lt;strong&gt;Chapter 8: Event-driven systems&lt;/strong&gt;. This 100+ page monster covers the philosophy of event-driven architectures and then gets practical with SQS, EventBridge, and Kinesis Data Streams. We upgraded our running URL shortener example to behave like a proper production system: offloading work to async flows, making it more extensible, and showing real trade-offs. Alongside Chapter 8, we also did a comprehensive pass across the entire manuscript, settling on British English (I suggested &lt;em&gt;Italenglish&lt;/em&gt;, but James wasn’t having it…), simplifying Rust snippets, and adding more security and production warnings.&lt;/p&gt;
&lt;p&gt;And we’re not done yet! We’re almost ready to publish a new chapter dedicated to &lt;strong&gt;observability&lt;/strong&gt; with Rust, Lambda, and OpenTelemetry. All the content is written and there’s quite a lot of it—we’re now in the reviewing and refining phase, just adding the finishing touches. Stay tuned for early 2026!&lt;/p&gt;
&lt;p&gt;Our plan for 2026 is to complete the book and, hopefully, make it available as a printed edition too. Stay tuned!&lt;/p&gt;
&lt;p&gt;By the way, I now have a &lt;a href=&quot;/books&quot;&gt;dedicated page for all my books&lt;/a&gt; on this site. Check it out if you want to see what else I’ve been writing!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There is nothing to writing. All you do is sit down at a typewriter and bleed.&lt;br&gt;
― Ernest Hemingway&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;approaching-5-years-of-growth-at-fourtheorem&quot;&gt;Approaching 5 years of growth at FourTheorem&lt;/h2&gt;
&lt;p&gt;Phew, almost 5 years! In February 2026 I’ll hit the five-year mark at &lt;a href=&quot;https://fourtheorem.com/&quot;&gt;FourTheorem&lt;/a&gt;, and yet it still feels like a fresh and welcoming place every single day. Tons of exciting projects, great people to work with, and countless opportunities to grow. Every day brings a new lesson. So let me take a minute to thank &lt;a href=&quot;https://www.linkedin.com/in/peterelger/&quot;&gt;Peter&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/fiona-mc-kenna-174172a2/&quot;&gt;Fiona&lt;/a&gt;, and &lt;a href=&quot;https://www.linkedin.com/in/eoins/&quot;&gt;Eoin&lt;/a&gt;, the minds, souls, and hearts behind FourTheorem, for creating such an amazing place to work at. Looking forward to many more years of collaboration and growth together!&lt;/p&gt;
&lt;p&gt;If you’ve never heard of FourTheorem before, we are an AWS consulting partner specialising in serverless-first architectures and application modernisation. We help organisations move to the cloud, optimise their infrastructure, and build scalable, cost-effective solutions. If you want to know more, check out our &lt;a href=&quot;https://fourtheorem.com/&quot;&gt;website&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Throughout 2025 I had the pleasure to work on a super ambitious and fun project. I can’t fully disclose all the details yet, but what I can tell you is that it was a &lt;strong&gt;multi-brand e-commerce-like platform&lt;/strong&gt; where I got to exercise pretty much all my programming muscles: backend APIs with Node.js and TypeScript (running on Lambda), data modelling with DynamoDB, frontend components with React and Next.js, and infrastructure as code with AWS CDK. It was a blast and I learned a ton! The best part? The whole system is configurable and allows you to deploy multiple brands from the same codebase, each with different themes, products, and even custom features such as payment gateways or quote engines. Super cool stuff, and I’m really proud of the results.&lt;/p&gt;
&lt;p&gt;This project also gave me the chance to experiment with some exciting new technologies: fully static client-side autocompletion widgets using &lt;a href=&quot;https://orama.com/&quot;&gt;Orama&lt;/a&gt;, &lt;a href=&quot;https://tanstack.com/query&quot;&gt;TanStack Query&lt;/a&gt; for data fetching, &lt;a href=&quot;https://zod.dev/&quot;&gt;Zod&lt;/a&gt; for schema validation, and an API-first design approach using &lt;a href=&quot;https://typespec.io/&quot;&gt;TypeSpec&lt;/a&gt; to generate models and clients from the spec.&lt;/p&gt;
&lt;p&gt;Overall, this was probably one of the coolest full-stack JavaScript/TypeScript serverless projects I’ve worked on in a while, and I’m super grateful to FourTheorem and our customer for trusting me with it and giving me the freedom to explore and learn new things.&lt;/p&gt;
&lt;p&gt;Now I’m excited to see what 2026 has in store for us at FourTheorem! The team and the customer base are steadily growing, and new opportunities are popping up all the time. Stay tuned for more updates and chances for me to share my learnings!&lt;/p&gt;
&lt;p&gt;P.S. We are always hiring at FourTheorem! If you’re a passionate developer looking for a great place to work, check out our &lt;a href=&quot;https://fourtheorem.com/careers&quot;&gt;careers page&lt;/a&gt; and reach out!&lt;/p&gt;
&lt;p&gt;P.P.S. This year we also got a &lt;strong&gt;new logo&lt;/strong&gt;! I hope you’ll get used to it and still recognize us!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;fourTheorem&amp;amp;#x27;s new logo in 2025&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;576&quot; src=&quot;https://loige.co/_astro/fourtheorem-new-logo-2025.DKAuDQcC_ZXjRlK.webp&quot; &gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Think like a proton. Always positive.&lt;br&gt;
— Unknown&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;keeping-the-aws-conversation-going-with-aws-bites&quot;&gt;Keeping the AWS conversation going with AWS Bites&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://awsbites.com/&quot;&gt;AWS Bites&lt;/a&gt; is the show I run with &lt;a href=&quot;https://www.linkedin.com/in/eoins/&quot;&gt;Eoin&lt;/a&gt; (from FourTheorem) where we chat about AWS topics in short, bite-sized episodes. Well, sometimes not too bite-sized… but we try to find a good balance between comprehensiveness and brevity!&lt;/p&gt;
&lt;p&gt;In 2025 we’ve been less consistent than previous years (busy times!), but we kept going and that’s what matters. We released &lt;strong&gt;13 new episodes&lt;/strong&gt; covering a variety of AWS topics. My favourite episode, and probably the one that got the most traction, was &lt;a href=&quot;https://awsbites.com/138-how-do-you-become-a-cloud-architect/&quot;&gt;138. How Do You Become A Cloud Architect?&lt;/a&gt;.&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://www.youtube.com/embed/Ruz_hDcyhz0&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;The numbers keep growing: we’ve almost reached &lt;strong&gt;4.5k subscribers&lt;/strong&gt; and &lt;strong&gt;160k views&lt;/strong&gt; on &lt;a href=&quot;https://www.youtube.com/@AWSBites&quot;&gt;YouTube&lt;/a&gt;, plus &lt;strong&gt;3.3k followers&lt;/strong&gt; and &lt;strong&gt;75k plays&lt;/strong&gt; on &lt;a href=&quot;https://open.spotify.com/show/3Lh7PzqBFV6yt5WsTAmO5q&quot;&gt;Spotify&lt;/a&gt;. In total, we’ve reached &lt;strong&gt;168k plays&lt;/strong&gt; across all platforms (as monitored by Spotify)!&lt;/p&gt;
&lt;p&gt;As always, it’s been a lot of fun to create the cover art for every episode. I expected AI would remove some of the fun, but it’s actually making it easier to experiment with different styles and ideas. I still do the final touches (and sometimes even more) manually though! I hope people enjoy the cover arts as much as I enjoy making them. If you want to see all of them, you’ll find them on the &lt;a href=&quot;https://awsbites.com/&quot;&gt;official website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There have been lots of interesting announcements during the last re:Invent in Vegas, like Lambda Durable Functions and Lambda Managed Instances. We’ll surely cover those as soon as possible! If you’re interested in these topics (and AWS in general), make sure to follow us on whatever podcast channel you prefer!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There was a star riding through clouds one night, and I said to the star, “Consume me”.&lt;br&gt;
― Virginia Woolf&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;spreading-knowledge-on-stage-and-online&quot;&gt;Spreading knowledge on stage (and online)&lt;/h2&gt;
&lt;p&gt;This year I did a bit less public speaking than usual. Between book writing and wanting to spend more time with family (and travel less), I had to be more selective with my engagements. Still, I managed to deliver &lt;strong&gt;8 different talks&lt;/strong&gt; throughout the year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/speaking/static-apis-coderful/&quot;&gt;&lt;strong&gt;Those unknown Static APIs&lt;/strong&gt;&lt;/a&gt; at Coderful (Aci Castello, Italy) - January 24&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/speaking/serverless-rust-rust-global-2025/&quot;&gt;&lt;strong&gt;Serverless Rust: Your Low-Risk Entry Point to Rust in Production&lt;/strong&gt;&lt;/a&gt; at Rust Global (London, England) - February 21&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/speaking/rust-and-aws-serverless-gbe-podcast/&quot;&gt;&lt;strong&gt;Let’s talk about Rust: Rust and AWS Serverless with Luciano&lt;/strong&gt;&lt;/a&gt; at GBE Podcast (Remote) - March 27&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/speaking/saas-on-aws-serverless-aws-community-day-italy-2025/&quot;&gt;&lt;strong&gt;Building Secure and Efficient SaaS Platforms on AWS Serverless&lt;/strong&gt;&lt;/a&gt; at AWS Community Day Italy (Milan, Italy) - April 2&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/speaking/aws-lambda-rust-to-the-rescue-aws-ug-catania/&quot;&gt;&lt;strong&gt;AWS Lambda: Rust to the Rescue&lt;/strong&gt;&lt;/a&gt; at AWS User Group Catania (Remote) - April 17&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/speaking/sviluppatore-senior-il-podcast-open-source/&quot;&gt;&lt;strong&gt;Sviluppatore Senior&lt;/strong&gt;&lt;/a&gt; at Il Podcast Open Source (Remote) - May 7&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/speaking/rust-roundtable-francesco-ciulla/&quot;&gt;&lt;strong&gt;Rust Roundtable&lt;/strong&gt;&lt;/a&gt; at Francesco Ciulla’s Channel (Remote) - May 30&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/speaking/nodejs-design-patterns-4th-edition-ama-packt-webinar/&quot;&gt;&lt;strong&gt;Node.js Design Patterns (4th ed) AMA Session&lt;/strong&gt;&lt;/a&gt; at Packt Webinar (Remote) - November 13&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By the way, I recently updated this website to have a dedicated page for each talk, where you can find slides and video recordings when available. Check out the &lt;a href=&quot;/speaking/&quot;&gt;speaking page&lt;/a&gt; for the full archive!&lt;/p&gt;
&lt;p&gt;My favourite talk of the year was probably the closing keynote I delivered with &lt;a href=&quot;https://jameseastham.co.uk/&quot;&gt;James Eastham&lt;/a&gt; at &lt;strong&gt;Rust Global 2025&lt;/strong&gt; in London. It was an honour to share the stage with James and talk about our journey with Rust and AWS Lambda to such an engaged audience.&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://www.youtube.com/embed/xLatWq6D6g4&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;After many years travelling a lot for conferences, I still have to evaluate how much travel I’m willing to do in 2026. Part of me is eager to get back in full swing into the conferences game, while the other is enjoying a more relaxed lifestyle. We’ll see what the new year will bring. I don’t need to take this decision in a rush. Meanwhile, if there’s a cool conference you want to invite me to, make sure to reach out. I will definitely consider it!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Share your knowledge. It’s a way to achieve immortality.&lt;br&gt;
– Dalai Lama&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;reaching-450-issues-of-fullstack-bulletin&quot;&gt;Reaching 450 issues of FullStack Bulletin&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://fullstackbulletin.com/&quot;&gt;FullStack Bulletin&lt;/a&gt; is a free weekly newsletter I co-founded with &lt;a href=&quot;https://andreamangano.com/&quot;&gt;Andrea Mangano&lt;/a&gt;. Every week we hand-pick &lt;strong&gt;7 curated articles&lt;/strong&gt; (sometimes more 😌) on full-stack web development and related topics, plus a book recommendation and an inspirational tech quote. It’s our way of helping fellow developers stay current with all the good stuff happening in our industry.&lt;/p&gt;
&lt;p&gt;Last year I wasn’t sure whether to keep it going or not, but eventually I decided to push through and I’m glad I did. I actually managed to stay quite consistent, publishing a new issue almost every week and reaching the astounding number of 450 issues published in total!&lt;/p&gt;
&lt;p&gt;I also invested some time in modernising the infrastructure: we moved away from Mailchimp to &lt;a href=&quot;https://buttondown.com/&quot;&gt;Buttondown&lt;/a&gt;. This made things a bit smoother and easier to manage. On top of that, I changed the format a little bit. I’m now investing a lot more time to make the selected content feel more curated and personal. If you’ve been reading the newsletter for the last few months, you probably noticed this change: I’m trying to explain why I liked each particular piece and identify broader themes across different articles. Let me know if you liked the new format!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://buttondown.com/fullstackbulletin/archive/444-finding-mr-tiff/&quot;&gt;&lt;img alt=&quot;FullStack Bulletin new format on Buttondown&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;736&quot; src=&quot;https://loige.co/_astro/fullstack-bulletin-new-format-on-buttondown-2025.CL6-kBg6_1vG7QD.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;From a growth perspective, the newsletter is still growing slowly but steadily. Right now we have about &lt;strong&gt;3,000 subscribers&lt;/strong&gt;, which is not a lot, but it’s a nice community of folks who seem to genuinely enjoy the content we share. I have gladly noticed that lately people are more engaged and likely to reach out. I love that, so please keep doing it, keep replying to the newsletter, and keep sharing your thoughts!&lt;/p&gt;
&lt;p&gt;We’re always looking for sponsors to help cover the costs of running the newsletter and maybe make it sustainable in the long run. If you’re interested, &lt;a href=&quot;mailto:luciano@fullstackbulletin.com&quot;&gt;reach out&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;For 2026, I’m hoping to keep the momentum going and maybe hit 500 issues. I’d also love to figure out how to grow the audience base a little faster. I think this newsletter would be much more valuable if it hit 6,000 subscribers, and it would also be much easier to attract sponsors and for me to dedicate more time to it, making it even more valuable for everyone. If you have suggestions on how to grow, I’m all ears! Another way you can help is by &lt;a href=&quot;https://fullstackbulletin.com/&quot;&gt;subscribing to the newsletter&lt;/a&gt; and sharing it with your friends!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Love only grows by sharing.&lt;br&gt;
— Brian Tracy&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;not-really-live-coding-on-twitch&quot;&gt;(Not really) live coding on Twitch&lt;/h2&gt;
&lt;p&gt;One of the side projects I’ve kept going over the last few years has been weekly coding live streams with my friend &lt;a href=&quot;https://github.com/gambuzzi&quot;&gt;Roberto Gambuzzi&lt;/a&gt;. We generally use these sessions as an excuse to run various experiments and learn Rust together, though occasionally we play with other technologies too (like Zig!).&lt;/p&gt;
&lt;p&gt;Not a very productive year on this front, I have to admit. Roberto and I managed to do only &lt;strong&gt;one live stream&lt;/strong&gt; this year!&lt;/p&gt;
&lt;div style=&quot; position: relative; padding-bottom: 56.25%; height: 0; margin-bottom: 5em;&quot;&gt;
&lt;iframe style=&quot;position: absolute; top:0; left: 0; width: 100%; height: 100%;&quot; src=&quot;https://www.youtube.com/embed/2AlioCMxsFU&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;This is mostly due to lack of time and energy on my side. Hopefully 2026 will be better and we’ll manage to resume streaming more consistently! I certainly missed our fun times learning Rust together and building things live.&lt;/p&gt;
&lt;p&gt;If you want to stay tuned for future streams, make sure to follow us on &lt;a href=&quot;https://www.twitch.tv/loige&quot;&gt;Twitch&lt;/a&gt; and subscribe to the &lt;a href=&quot;https://www.youtube.com/@Loige&quot;&gt;YouTube channel&lt;/a&gt; where we upload all the recordings!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The only way to learn a new programming language is by writing programs in it.&lt;br&gt;
— Dennis Ritchie&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;writing-just-a-few-articles-and-blog-posts&quot;&gt;Writing (just a few) articles and blog posts&lt;/h2&gt;
&lt;p&gt;Not the most prolific year for blogging, I have to admit. Between working on two books and everything else going on, I didn’t have much time or energy left for writing articles. Still, I managed to publish a few pieces:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On this blog:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/2024-a-year-in-review&quot;&gt;2024 - A year in Review&lt;/a&gt; - My annual tradition of looking back at the previous year&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/debugging-api-gateway-http-oidc-jwt-authorizer&quot;&gt;Debugging AWS API Gateway HTTP with OIDC-JWT authorizers&lt;/a&gt; - A quick post about a frustrating debugging session that taught me about the &lt;code&gt;FailOnWarnings&lt;/code&gt; option&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/nodejs-design-patterns-fourth-edition&quot;&gt;Node.js Design Patterns Fourth Edition&lt;/a&gt; - The announcement for the new edition of the book&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;On external sites:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejsdesignpatterns.com/blog/reading-writing-files-nodejs/&quot;&gt;Reading and Writing Files in Node.js - The Complete Modern Guide&lt;/a&gt; - A comprehensive guide published on the Node.js Design Patterns website&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s just &lt;strong&gt;4 articles&lt;/strong&gt; in total. Not great, but quality over quantity, right? Hopefully 2026 will be a more productive year on this front!&lt;/p&gt;
&lt;p&gt;One thing that I have found interesting is that I found myself leaning a lot more than I could ever anticipate on AI for writing. I know this might sound controversial, but hear me out: I don’t just delegate &lt;em&gt;all&lt;/em&gt; my writing to AI. Instead, I make a first pretty detailed draft and then let the AI do a first pass at polishing the text, fixing grammar, and improving flow. After that, I do a final pass myself to make sure everything sounds like me and that the technical details are accurate. This approach has saved me a ton of time and effort, allowing me to focus more on the content rather than getting bogged down in the writing process. Admittedly, writing in English, which is not my mother tongue, can be more challenging and time-consuming than I’d like it to be. It’s been a game-changer for me, and I plan to keep using it in the future! This is something I started doing only in the last few months of 2025, so it’ll be interesting to see how this evolves in 2026. Hopefully it will allow me to create more content without sacrificing quality throughout 2026!&lt;/p&gt;
&lt;p&gt;PS: here’s a screenshot from my usage of Claude Code, which I am finding particularly useful for these kinds of tasks (other than coding tasks)!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;My Claude Code stats for 2025&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1280&quot; height=&quot;636&quot; src=&quot;https://loige.co/_astro/my-claude-code-stats-for-2025.DmGJNmu0_1DKvEv.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;My longest session is ~96x longer than a transatlantic flight… LOL!&lt;/small&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It’s harder to read code than to write it.&lt;br&gt;
— Joel Spolsky&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;contributing-to-open-source&quot;&gt;Contributing to Open Source&lt;/h2&gt;
&lt;p&gt;I always like to do some open source whenever I have the chance. I like to contribute to projects I use (even in small ways) and I like to share almost everything I do in an open-source fashion. No surprise that I kept my commit race going in 2025… not in a crazy way, but it was great to be able to keep things going.&lt;/p&gt;
&lt;p&gt;In 2025 I created &lt;strong&gt;68 Pull Requests&lt;/strong&gt; and &lt;strong&gt;11 new public repositories&lt;/strong&gt;. Here’s a list of my most meaningful contributions:&lt;/p&gt;
&lt;h3 id=&quot;new-projects&quot;&gt;New projects&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/s3-migrate&quot;&gt;&lt;code&gt;lmammino/s3-migrate&lt;/code&gt;&lt;/a&gt;: A CLI to help you move all your objects between S3-compatible storage systems. This one got &lt;strong&gt;34 stars&lt;/strong&gt; already!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/tinyb36&quot;&gt;&lt;code&gt;lmammino/tinyb36&lt;/code&gt;&lt;/a&gt;: A tiny Rust crate to convert an integer to its string representation using a base-36 encoding scheme.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/rental-station-static-api-demo&quot;&gt;&lt;code&gt;lmammino/rental-station-static-api-demo&lt;/code&gt;&lt;/a&gt;: A simple demo to showcase the concept of static APIs (with full-text search using Orama!). This is something I created as a demo for my talk &lt;a href=&quot;/speaking/static-apis-coderful/&quot;&gt;Those unknown Static APIs
&lt;/a&gt; presented this year at Coderful.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/geo-redirect-lambda&quot;&gt;&lt;code&gt;lmammino/geo-redirect-lambda&lt;/code&gt;&lt;/a&gt;: A Lambda function written in Rust to redirect users to specific URLs depending on their geographic location.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/reading-and-writing-files-with-nodejs-examples&quot;&gt;&lt;code&gt;lmammino/reading-and-writing-files-with-nodejs-examples&lt;/code&gt;&lt;/a&gt;: Code examples for the article on reading and writing files with Node.js. Created for &lt;a href=&quot;https://nodejsdesignpatterns.com/blog/reading-writing-files-nodejs/&quot;&gt;an article published on the Node.js Design Patterns website&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/sample-events-website&quot;&gt;&lt;code&gt;lmammino/sample-events-website&lt;/code&gt;&lt;/a&gt;: A sample demo website where you can browse events and book your ticket. This one was quickly vibe-coded and used as an example for writing end-to-end tests with Playwright. Something I needed for the chapter dedicated to testing in the fourth edition of Node.js Design Patterns.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/can-you-renew-your-italian-passport-abroad&quot;&gt;&lt;code&gt;lmammino/can-you-renew-your-italian-passport-abroad&lt;/code&gt;&lt;/a&gt;: Automation that checks if there are spots available to renew your Italian passport at your local embassy (anyone who tried to renew their Italian passport abroad knows the struggle!)… yes, this year I also needed to renew my passport!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/rebrandly-links-export&quot;&gt;&lt;code&gt;lmammino/rebrandly-links-export&lt;/code&gt;&lt;/a&gt;: A tool to export your links from Rebrandly. Sadly, I moved away from Rebrandly this year and wanted to have a local backup of all my links and a way to migrate them elsewhere.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/homebrew-tap&quot;&gt;&lt;code&gt;lmammino/homebrew-tap&lt;/code&gt;&lt;/a&gt;: My personal Homebrew tap for distributing CLI tools. Right now I am using it to publish &lt;code&gt;jwtinfo&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/codecrafters-kafka&quot;&gt;&lt;code&gt;lmammino/codecrafters-kafka&lt;/code&gt;&lt;/a&gt;: My solution for the Codecrafters Kafka challenge in Rust. Mostly incomplete…&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;contributions-to-external-projects&quot;&gt;Contributions to external projects&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/aws/aws-lambda-rust-runtime/pull/1063&quot;&gt;&lt;code&gt;aws/aws-lambda-rust-runtime&lt;/code&gt;&lt;/a&gt;: Improved ergonomics of &lt;code&gt;SqsBatchResponse&lt;/code&gt; and &lt;code&gt;KinesisEventResponse&lt;/code&gt; for the official AWS Lambda Rust runtime.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vercel/next.js/pull/80942&quot;&gt;&lt;code&gt;vercel/next.js&lt;/code&gt;&lt;/a&gt;: Documentation update for the backend-for-frontend pattern.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/middyjs/middy/pull/1335&quot;&gt;&lt;code&gt;middyjs/middy&lt;/code&gt;&lt;/a&gt;: Updated fourTheorem logo on the Middy website.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fastify/fastify-vite/pull/224&quot;&gt;&lt;code&gt;fastify/fastify-vite&lt;/code&gt;&lt;/a&gt;: Documentation improvements for project structure and getting started guide.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;contributions-to-own-projects&quot;&gt;Contributions to own projects&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/jwtinfo&quot;&gt;&lt;code&gt;lmammino/jwtinfo&lt;/code&gt;&lt;/a&gt;: Added support for JWE tokens, &lt;code&gt;--full&lt;/code&gt; flag to display both header and claims, and improved the publishing process using &lt;code&gt;dist&lt;/code&gt;. Also opened issues for future JWE decryption support and library restructuring.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lmammino/primitive&quot;&gt;&lt;code&gt;lmammino/primitive&lt;/code&gt;&lt;/a&gt;: A fork of the original &lt;code&gt;primitive&lt;/code&gt; by Michael Fogleman. This tool reproduces images using geometric primitives and I use it to generate header images for this blog. I updated the fork to keep it compatible with recent versions of the Go compiler.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FullStackBulletin/automation&quot;&gt;&lt;code&gt;FullStackBulletin/automation&lt;/code&gt;&lt;/a&gt;: Fixed failing tests and general maintenance. Migrated the newsletter system to Buttondown (from Mailchimp).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To close this section here’s my ritual GitHub yearly contribution graph! I know it’s just vanity, but it’s fun!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;GitHub contribution chart of Luciano Mammino (lmammino) in 2025&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1520&quot; height=&quot;410&quot; src=&quot;https://loige.co/_astro/lmammino-github-contribution-chart-2025.D6cQ0FcE_Z23uFfS.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;For 2026, I’m hoping to keep the momentum going. I have a few ideas for new projects and I’d love to contribute more to some of the tools I use daily. Let’s see what the new year will bring!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Open source is a public good and across every industry, we have a responsibility to come together to improve and support the security of open-source software we all depend on.&lt;br&gt;
— Jim Zemlin&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;watching-middy-thrive&quot;&gt;Watching Middy thrive&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://middy.js.org/&quot;&gt;Middy&lt;/a&gt; is a Node.js middleware engine for AWS Lambda. It helps you organise your Lambda code by separating business logic from cross-cutting concerns like authentication, validation, error handling, and serialization. Think of it as a way to keep your handlers clean and focused while reusable middleware takes care of all the boilerplate.&lt;/p&gt;
&lt;p&gt;While I originally created Middy a few years ago, I haven’t been much involved in recent years since &lt;a href=&quot;https://github.com/willfarrell&quot;&gt;Will Farrell&lt;/a&gt; stepped up as main maintainer. So this section is more about tracking the progress of Middy than me being able to take any credit for it!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Version 7 is coming!&lt;/strong&gt; There’s already an &lt;a href=&quot;https://github.com/middyjs/middy/releases/tag/7.0.0-alpha.3&quot;&gt;alpha release&lt;/a&gt; available. I’m particularly excited to see that it adds support for &lt;strong&gt;&lt;a href=&quot;https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html&quot;&gt;Durable Functions&lt;/a&gt;&lt;/strong&gt; in AWS Lambda. This is a testament to how hard Will is pushing to keep Middy relevant and up to date: Durable Functions was only announced at re:Invent 2025, less than a month ago!&lt;/p&gt;
&lt;p&gt;Middy is still the leading framework in this space, approaching &lt;strong&gt;600k weekly downloads&lt;/strong&gt; on npm!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://npmtrends.com/@codegenie/serverless-express-vs-@fastify/aws-lambda-vs-@middy/core-vs-@vendia/serverless-express-vs-aws-lambda-fastify-vs-aws-serverless-express-vs-lambda-api-vs-serverless-express-vs-serverless-http&quot;&gt;&lt;img alt=&quot;Middy downloads chart vs competitors&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1280&quot; height=&quot;456&quot; src=&quot;https://loige.co/_astro/middyjs-downloads-chart-vs-competitors.BXzEz5MC_Z24hs03.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;small&gt;
&lt;p&gt;Multi-series time-series chart (Jan–Dec 2025, 0–600k) comparing package usage/download trends. &lt;strong&gt;@middy/core&lt;/strong&gt; leads throughout, rising from ~400k to nearly &lt;strong&gt;600k&lt;/strong&gt; by December. A second tier (&lt;strong&gt;serverless-express&lt;/strong&gt;, &lt;strong&gt;@codegenie/serverless-express&lt;/strong&gt;, &lt;strong&gt;@vendia/serverless-express&lt;/strong&gt;) sits mostly in the &lt;strong&gt;~300k–420k&lt;/strong&gt; range, with a brief dip around early October before recovering. &lt;strong&gt;serverless-http&lt;/strong&gt; climbs from ~180k to ~300k mid/late year, while &lt;strong&gt;aws-serverless-express&lt;/strong&gt; trends down toward ~150k. The remaining packages stay below &lt;strong&gt;~100k&lt;/strong&gt;.&lt;/p&gt;
&lt;/small&gt;
&lt;p&gt;The project is also close to &lt;strong&gt;4,000 stars&lt;/strong&gt; on GitHub (currently at 3,877). If you like Middy, make sure to &lt;a href=&quot;https://github.com/middyjs/middy&quot;&gt;give it a star&lt;/a&gt;! Even better, consider &lt;a href=&quot;https://github.com/sponsors/willfarrell&quot;&gt;sponsoring Will&lt;/a&gt; to support the project and keep it thriving!&lt;/p&gt;
&lt;p&gt;For 2026, I expect version 7 to be released and I’m curious to see how the community will adopt the new Durable Functions support. I might also try to get more involved again, at least to help with documentation and community support. Let’s see how things unfold!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We shape our tools, and thereafter our tools shape us.&lt;br&gt;
— Marshall McLuhan&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;some-other-random-stuff&quot;&gt;Some other random stuff&lt;/h2&gt;
&lt;p&gt;This year (in December) I renewed my &lt;a href=&quot;https://aws.amazon.com/certification/certified-solutions-architect-professional/&quot;&gt;AWS Certified Solutions Architect – Professional&lt;/a&gt; certification which had expired early this April. Always good to keep these things up to date! I didn’t write a detailed article about it this time because, I have to admit, I had to wing it a little bit and I think I was lucky enough to pass it at the first try! This one is always a very challenging exam: a full half day of intense brain work. If you want to know more about how I prepared for it in the past, check out my &lt;a href=&quot;/2022-a-year-in-review&quot;&gt;2022 year in review&lt;/a&gt; where I wrote a bit more about my approach.&lt;/p&gt;
&lt;p&gt;I’m now studying for the &lt;a href=&quot;https://aws.amazon.com/certification/certified-ai-practitioner/&quot;&gt;AWS Certified AI Practitioner&lt;/a&gt;, because it seems like a fun one and I’m curious to learn more about what AWS has to offer when it comes to generative AI. Things are stabilising a little bit in the AI space and I’m starting to see real projects where we can leverage AI for good reasons, not just because it sounds cool (or excites investors) to say we did!&lt;/p&gt;
&lt;p&gt;Now a little bit of bad news: I am not an MVP anymore… or should I say I am now a &lt;em&gt;former&lt;/em&gt; MVP (as they suggest in their goodbye letter)? My MVP status was not renewed this year. Unfortunately, you don’t get much feedback on why, so I could only speculate… but I’m not going to do that. I’m just going to say it was a fun ride while it lasted, and I’m grateful for all the opportunities and connections it brought me. Onwards and upwards!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Screenshot of a Microsoft MVP Communities email titled &amp;amp;#x27;MVP Annual Review Update&amp;amp;#x27; addressed to Luciano Mammino, stating the MVP award will not be renewed and highlighting instructions to update his status to &amp;amp;#x27;former&amp;amp;#x27;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1280&quot; height=&quot;1343&quot; src=&quot;https://loige.co/_astro/microsoft-telling-luciano-mammino-he-doesnt-deserve-to-be-an-mvp-anymore.BRbvYqQ3_Z1AIS4G.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Here you can see the full email I received from Microsoft! Well, goodbye MVP program, it was nice knowing you!&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;On the bright side, I’m still a &lt;a href=&quot;https://www.codemotion.com/&quot;&gt;Codemotion Ambassador&lt;/a&gt; and happy to support one of the coolest tech communities out there (and definitely the biggest/coolest tech conference in Italy)!&lt;/p&gt;
&lt;p&gt;For 2026, I’m hoping to pass the AI Practitioner exam and maybe tackle one more certification. We’ll see how much time I’ll have for studying, but it’s always fun to learn new things and keep my skills sharp!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Success is the sum of small efforts, repeated day in and day out.&lt;br&gt;
— Robert Collier&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;some-more-personal-achievements&quot;&gt;Some more personal achievements&lt;/h2&gt;
&lt;p&gt;I kept training quite consistently this year and in June I finally got promoted to &lt;strong&gt;Brown Belt in Brazilian Jiu-Jitsu&lt;/strong&gt;! After years of training and dedication, I finally achieved this milestone. It’s been a challenging journey, but every step has been worth it. Huge thanks to my coaches and training partners for their support and guidance along the way. I honestly don’t feel like I deserve it, but that’s the way it’s supposed to be… at least if I listen to more experienced practitioners! 🤙&lt;/p&gt;
&lt;p&gt;I didn’t run much this year and Strava got a bit disappointed with me! But the good news is that I got to spend some time with family in Rome, and that’s where during the summer break I managed to squeeze in a few running sessions. I finally ran around the Colosseum and the Roman Forum, which had been on my bucket list for a while! Such an incredible experience to run through such historic landmarks. Definitely a highlight of my year!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Left: A photo of Luciano Mammino and Jorge Santos at the Brown Belt graduation ceremony in Dublin. Right: A photo of Luciano Mammino running around the Colosseum in Rome&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;477&quot; src=&quot;https://loige.co/_astro/luciano-mammino-bjj-graduation-brown-belt-and-running-in-rome.CNFrLjlR_2m9tTI.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;In the picture above, on the left it’s a photo of me with my coaches Jorge Santos and Xandy right after the graduation ceremony in Dublin. Such a proud moment for me! (Sorry for the low res, but I had to cut this frame out from a social video!) On the right, you can see me running around the Colosseum in Rome. Such an epic backdrop for a run!&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;I also got to visit a few cool places. My favourites were Iceland, Paris, and the Italian Alps! I’ll leave you with some pics below. Can you geo-tag them all? 😉&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A frame with 3 pictures: Iceland (top left), Paris (right), and the Italian Alps (bottom left)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1024&quot; height=&quot;686&quot; src=&quot;https://loige.co/_astro/paris-iceland-italian-alps.C3_DAWzx_ZtprLm.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;And now onto the biggest news and gift of 2025… &lt;strong&gt;I became a dad!&lt;/strong&gt; Yes, in September 2025 my wife and I welcomed our first child into our family. It’s been an incredible journey so far, filled with joy, challenges, and countless unforgettable moments. Parenthood is a whole new adventure, and I’m embracing every bit of it. Looking forward to all the milestones and memories to come! And sorry ahead of time if this means I’ll be less productive and less present online and at various in-person events… but hey, priorities, right?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A photo of Luciano Mammino smiling with his son. The face of the baby is covered with a heart eyes emoji&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;600&quot; height=&quot;800&quot; src=&quot;https://loige.co/_astro/luciano-mammino-and-his-son.U-9cbwoN_mCtaO.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Isn’t he cute when he smiles? 😍&lt;/small&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Life is what happens when you’re busy making other plans.&lt;br&gt;
— John Lennon&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;wrapping-up-the-wrap-up&quot;&gt;Wrapping up the wrap up 🌯🌯&lt;/h2&gt;
&lt;p&gt;This year was a fantastic year full of learning, growth, and joy. I couldn’t ask for anything better and it will be hard to match it in 2026. But let’s be hopeful and keep pushing forward! I will certainly try my best on the things I can control!&lt;/p&gt;
&lt;p&gt;I certainly wouldn’t be where I am today without the support of my family, friends, colleagues, and the amazing community around me. Thank you all for being part of my journey!&lt;/p&gt;
&lt;p&gt;OMG, are you still reading!? I think at this point you are either my mom or a serial stalker… or maybe both! Either way, thanks for sticking around till the end. I hope you found some interesting tidbits in my 2025 review. If you did, feel free to reach out and share your thoughts or just say hi… or even better, share some highlights of your 2025! You can also leave a comment below. Seriously, I always love hearing from readers!&lt;/p&gt;
&lt;p&gt;If you liked this post, you might also enjoy similar year-in-review recaps by fellow software engineers, fullstack devs, and overall awesome human beings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://bell.bz/wrapping-up-2025-sort-of/&quot;&gt;Wrapping up 2025 (sort of)&lt;/a&gt; by Andy Bell&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://joshcollinsworth.com/blog/2025&quot;&gt;2025 Year in Review&lt;/a&gt; by Josh Collingsworth&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dbushell.com/2025/12/18/year-in-review/&quot;&gt;I Survived 2025&lt;/a&gt; by David Bushell&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vale.rocks/pulse/2025&quot;&gt;Feeling The Pulse of Twenty Twenty-Five&lt;/a&gt; by Declan Chidlow&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://colly.com/journal/twenty-twentyfive-in-music&quot;&gt;2025 in music&lt;/a&gt; by Simon Collison&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://flamedfury.com/posts/books-i-read-in-2025/&quot;&gt;Books I Read in 2025&lt;/a&gt; by Flamed Fury&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hidde.blog/2025-review/&quot;&gt;My 2025 review&lt;/a&gt; by Hidde de Vries&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.coryd.dev/posts/2025/2025-in-review&quot;&gt;2025 in review&lt;/a&gt; by Cory Dransfeldt&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pawelgrzybek.com/a-look-back-at-2025&quot;&gt;Look Back at 2025&lt;/a&gt; by Paweł Grzybek&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nazhamid.com/journal/music-in-2025&quot;&gt;Music In 2025&lt;/a&gt; by Naz Hamid&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://chriskirknielsen.com/blog/yearnotes-2025&quot;&gt;Yearnotes 2025&lt;/a&gt; by Christopher Kirk-Nielsen&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ethanmarcotte.com/wrote/our-frail-thoughts/&quot;&gt;Our frail thoughts&lt;/a&gt; by Ethan Marcotte&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://aubreysambor.com/2025-year-in-review/&quot;&gt;2025 year in review&lt;/a&gt; by Aubrey Sambor&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/thank-you-2025-edition/&quot;&gt;Thank You (2025 Edition)&lt;/a&gt; by Geoff Graham&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://damianwalsh.co.uk/posts/2025-in-review/&quot;&gt;2025 in review&lt;/a&gt; by Damian Walsh&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://samwho.dev/2025&quot;&gt;2025&lt;/a&gt; by Sam Rose&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://thorstenbeeck.com/blog/2025-year-in-review/&quot;&gt;2025 Year in Review&lt;/a&gt; by Thorsten Beeck&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A quick thank you to everyone who has already mentioned this post!&lt;/p&gt;
&lt;p&gt;See you in 2026! Happy New Year! 🎉&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The secret to a good life is not to have what you want, but to want what you have.&lt;br&gt;
— Rabbi Hyman Schachtel&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><media:content url="https://loige.co/og/2025-a-year-in-review.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/2025-a-year-in-review.png" width="1200" height="630"/></media:content><category>life</category><author>Luciano Mammino</author><comments>https://loige.co/2025-a-year-in-review/#comments</comments><enclosure url="https://loige.co/og/2025-a-year-in-review.png" length="0" type="image/png"/></item><item><title>404: Newsletter Found</title><link>https://loige.co/404-newsletter-found/</link><guid isPermaLink="true">https://loige.co/404-newsletter-found/</guid><description>Discover the journey behind FullStack Bulletin, a weekly newsletter for full-stack developers with 404 curated issues over 8 years. Learn about its origins, technical implementation, and future plans.</description><pubDate>Sat, 21 Dec 2024 15:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Eight years ago, I embarked on a journey to make sense of the fast-paced,
ever-evolving world of full-stack web development. The result was FullStack
Bulletin, a weekly newsletter designed to keep developers informed and inspired.
With each issue, I aim to share a curated selection of articles, a recommended
book, and a thought-provoking quote, all tailored for full-stack developers and
those aspiring to join the field.&lt;/p&gt;
&lt;p&gt;In this article, to celebrate the milestone of reaching 404 published issues, I
decided to share the story behind FullStack Bulletin: why I created it, the
technical architecture that keeps it running, and my vision for the future.&lt;/p&gt;
&lt;p&gt;If you’re not already a subscriber, you can sign up at
&lt;a href=&quot;https://fullstackbulletin.com&quot;&gt;FullStackBulletin.com&lt;/a&gt; and join our wonderful
community of 3,000+ full-stack web developers around the world.&lt;/p&gt;
&lt;h2 id=&quot;why-fullstack-bulletin&quot;&gt;Why FullStack Bulletin?&lt;/h2&gt;
&lt;p&gt;I was fortunate to begin my coding journey at the age of 12, starting with
playful experiments using the qBasic interpreter. What began as a fun hobby
gradually transformed into a career when I started earning money by building
websites for friends and local businesses. I was captivated by the idea of
creating something out of nothing and inspired by the limitless possibilities
the web offered. However, building websites was no simple task then, just as it
isn’t today. The web is constantly evolving, and staying updated with new trends
and technologies remains an ongoing challenge.&lt;/p&gt;
&lt;p&gt;The full-stack development world is among the fastest-moving industries of the
past decade. It’s not just about front-end and back-end anymore—it’s about
mastering UI/UX design, product architecture, databases, and everything else
that goes into building amazing web experiences. Keeping up with this breadth of
knowledge is daunting, to say the least. I have experienced this firsthand, and
it’s still something that, even with my current level of seniority, I still
struggle with.&lt;/p&gt;
&lt;p&gt;And I am not alone in this. In fact, I started this project together with my
dear friend and ex-colleague &lt;a href=&quot;https://andreamangano.com/&quot;&gt;Andrea Mangano&lt;/a&gt;. We
originally designed the format together and Andrea is responsible for the
awesome look and feel that still represents FullStack Bulletin today.&lt;/p&gt;
&lt;p&gt;FullStack Bulletin is our way of making life a bit easier for full-stack
developers and those aspiring to join the field. Every week, we carefully curate
the most interesting and valuable content, delivering it straight to your inbox.
Since our launch in March 2017, our mission has been to help developers stay
informed and inspired.&lt;/p&gt;
&lt;p&gt;To us, FullStack Bulletin is the newsletter we wish we had when we started our
own full-stack development journey. It’s a platform to share knowledge, uncover
fascinating content, stay motivated, and spread our shared passion for web
development.&lt;/p&gt;
&lt;h2 id=&quot;behind-the-scenes-technical-implementation&quot;&gt;Behind the Scenes: Technical Implementation&lt;/h2&gt;
&lt;p&gt;Publishing a newsletter consistently every week is no easy feat. That’s why I’ve
relied on automation whenever possible, making FullStack Bulletin a
semi-automated newsletter.&lt;/p&gt;
&lt;p&gt;I know, some of my friends and colleagues often tease me for my tendency to
automate everything, maybe a little too much. They even like to refer to me with
this quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Never spend 6 minutes doing something by hand when you can spend 6 hours
failing to automate it&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;small&gt;I am not sure who is the original author, let me know if you
know!&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;But I believe that automation is key to keep things running smoothly and to free
up time for more important tasks, especially when you are planning to keep doing
something for the long run (and in your spare time)!&lt;/p&gt;
&lt;p&gt;However, not everything is fully automated. After all, who would want to read a
soulless, overly mechanical newsletter?&lt;/p&gt;
&lt;p&gt;The content selection remains a manual process. I personally gather interesting
articles throughout the week, and that’s where automation steps in. It scrapes
the links, fetches titles and descriptions, ranks the content, and creates a
draft for the next issue. This draft includes curated links, a rotating quote,
and a recommended book of the week. While automation handles the heavy lifting,
I still edit the draft manually to ensure quality and add a personal touch with
an editorial introduction before publishing.&lt;/p&gt;
&lt;p&gt;All automation runs on AWS using a Step Function, and the code is open source on
&lt;a href=&quot;https://github.com/FullStackBulletin/automation&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I have even done a series of live coding sessions on Twitch with my dear friend
&lt;a href=&quot;https://www.gambuzzi.it/&quot;&gt;Roberto Gambuzzi&lt;/a&gt; where we split the original
monolithic Lambda function into a Step Function and rewrote some of the
single-purpose Lambda functions in Rust! BTW, If you’re curious about the
broader topic of writing &lt;a href=&quot;/tag/lambda&quot;&gt;Lambda&lt;/a&gt; functions in &lt;a href=&quot;/tag/rust&quot;&gt;Rust&lt;/a&gt;,
you should definitely check out my previous article:
&lt;a href=&quot;/coauthoring-a-book-about-rust-and-lambda&quot;&gt;I am co-authoring a book about Rust and Lambda&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you’re interested in watching the live coding sessions, you can check out the
&lt;a href=&quot;https://www.youtube.com/playlist?list=PLbNOKnE-Oyr1tsUft4j0QZDyk5iFcVVy_&quot;&gt;“Fullstack bulletin fixes/remake” playlist on YouTube&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PLbNOKnE-Oyr1tsUft4j0QZDyk5iFcVVy_&quot;&gt;&lt;img alt=&quot;Fullstack bulletin fixes / remake&amp;quot; playlist on YouTube&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;336&quot; height=&quot;188&quot; src=&quot;https://loige.co/_astro/fullstack-bulletin-fixes-remake-youtube-playlist.DVyDYV5I_LKycY.webp&quot; &gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;static-apis-quotes-and-books&quot;&gt;Static APIs: Quotes and Books&lt;/h2&gt;
&lt;p&gt;One of the unique features of FullStack Bulletin is the inclusion of curated
recommendations for books and technical quotes that resonate with full-stack
developers. These aren’t just randomly selected: they represent resources and
insights that I find meaningful and relevant for anyone navigating this
ever-evolving field. To streamline the process of integrating this content into
the newsletter, I created static lists for both recommended books and technical
quotes, which are publicly available on GitHub:
&lt;a href=&quot;https://github.com/FullStackBulletin/tech-quotes&quot;&gt;tech-quotes&lt;/a&gt; and
&lt;a href=&quot;https://github.com/FullStackBulletin/fullstack-books&quot;&gt;fullstack-books&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These repositories serve as the foundation for an automated system. Each repo
contains the raw content files—simple text or data entries—that are processed by
GitHub Actions to generate a static JSON API. This automation takes care of
converting the raw data into a series of discrete JSON files. These files are
then hosted on a CDN through GitHub Pages, giving them predictable URLs that can
be easily accessed. Effectively a file-based API!&lt;/p&gt;
&lt;p&gt;For example, if you run:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;https://fullStackbulletin.github.io/tech-quotes/quotes/17.json&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;jq&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;curl https://fullStackbulletin.github.io/tech-quotes/quotes/17.json | jq .&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;You’ll get a JSON response like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;17&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;The art challenges the technology, and the technology inspires the art&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;john-lasseter&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;John Lasseter&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Director&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;wiki&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;https://en.wikipedia.org/wiki/John_Lasseter&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;https://fullStackbulletin.github.io/tech-quotes/authors/john-lasseter.json&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;https://fullStackbulletin.github.io/tech-quotes/quotes/17.json&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{  &amp;#x22;id&amp;#x22;: 17,  &amp;#x22;text&amp;#x22;: &amp;#x22;The art challenges the technology, and the technology inspires the art&amp;#x22;,  &amp;#x22;author&amp;#x22;: {    &amp;#x22;id&amp;#x22;: &amp;#x22;john-lasseter&amp;#x22;,    &amp;#x22;name&amp;#x22;: &amp;#x22;John Lasseter&amp;#x22;,    &amp;#x22;description&amp;#x22;: &amp;#x22;Director&amp;#x22;,    &amp;#x22;wiki&amp;#x22;: &amp;#x22;https://en.wikipedia.org/wiki/John_Lasseter&amp;#x22;,    &amp;#x22;url&amp;#x22;: &amp;#x22;https://fullStackbulletin.github.io/tech-quotes/authors/john-lasseter.json&amp;#x22;  },  &amp;#x22;url&amp;#x22;: &amp;#x22;https://fullStackbulletin.github.io/tech-quotes/quotes/17.json&amp;#x22;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The newsletter’s AWS Step Function (more on it later) make use of these static
APIs by fetching the “book of the week” and the “quote of the week” directly
from the CDN. This approach ensures that the content is dynamic and refreshes
seamlessly without requiring a database or a backend. It’s a lightweight yet
powerful way to include consistent, high-quality content in every issue.&lt;/p&gt;
&lt;p&gt;And here’s where this part of the project gets even better: it’s open to
community contributions! If you know of a technical book that has helped you
grow as a full-stack web developer or a quote that has inspired you, you’re
welcome to contribute. Just head over to the GitHub repositories, add your
suggestion, and submit a pull request. This collaborative aspect not only keeps
the recommendations fresh but also makes FullStack Bulletin a more inclusive
resource for the community it serves.&lt;/p&gt;
&lt;p&gt;PS: If you are curious to find out more about the topic of Static APIs, you
should be aware that I am delivering a talk about it at the next edition of
&lt;a href=&quot;https://www.coderful.io/&quot;&gt;Coderful Backend&lt;/a&gt; in January 2025 in the beautiful
Sicily (my homeland ❤️). If you can’t make it, don’t worry, I will make sure to
share the slides and the recording of the talk here on my blog!&lt;/p&gt;
&lt;h2 id=&quot;the-overall-architecture&quot;&gt;The Overall Architecture&lt;/h2&gt;
&lt;p&gt;Let’s visualize the current architecture of the automation by looking at the
diagram of the step function:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The Step Function running the automation of FullStack Bulletin every week&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1260&quot; height=&quot;700&quot; src=&quot;https://loige.co/_astro/fullstack-bulletin-step-function.CvFTxYhF_ZS64jB.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;So, here’s how it all comes together, step by step:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The first 2 steps (&lt;em&gt;Define Defaults&lt;/em&gt; and &lt;em&gt;Apply Defaults&lt;/em&gt;) are responsible
for setting up the default values for the automation, like fetching
configuration.&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;Fetch Issue Number&lt;/em&gt; step is responsible for fetching the latest issue
number. This is a bit of a hacky step, but it’s still in the spirit of
avoiding to have any &lt;em&gt;serverfull&lt;/em&gt; backend or a database. The idea is to crawl
the
&lt;a href=&quot;https://us15.campaign-archive.com/home/?u=b015626aa6028495fe77c75ea&amp;#x26;id=55ace33899&quot;&gt;page with the latest published issues&lt;/a&gt;
and extract the latest issue number from the list of issues. The next issue
will be that number + 1, of course!&lt;/li&gt;
&lt;li&gt;Now there’s the content fetching part. Here we branch out and load data from
4 different sources in parallel:
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Fetch Quote&lt;/em&gt;: This step fetches a random quote from the static API with
quotes.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Fetch Book&lt;/em&gt;: This step fetches a random book from the static API with
books.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Fetch Sponsors&lt;/em&gt;: This step fetches the sponsors information for the
current issue (more on this later). Behind the scenes it’s using an
&lt;em&gt;Airtable&lt;/em&gt; table as a backend. I admit I have been considering the idea of
moving this to a DynamoDB table or to a Google Spreadsheet, but I Airtable
keeps things simple, although I had
&lt;a href=&quot;/invite-only-microsites-with-nextjs-and-airtable/&quot;&gt;my fair share of issues with the Airtable APIs&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Fetch Links&lt;/em&gt;: This step fetches the content links from the
&lt;a href=&quot;https://mastodon.social/@fstackbulletin&quot;&gt;FullStack Bulletin Mastodon profile&lt;/a&gt;
(posts from the previous week that contain links) and ranks them based on
the number of interactions. Fun fact: this used to be done on Twitter…
until
&lt;a href=&quot;https://www.businessinsider.com/elon-musk-enters-twitter-headquarters-carrying-bathroom-sink-video-2022-10&quot;&gt;&lt;em&gt;someone&lt;/em&gt;&lt;/a&gt;
decided to make accessing Twitter APIs significantly more difficult and
(very) expensive.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The last step (&lt;em&gt;Create Issue&lt;/em&gt;) is responsible for creating the draft of the
email in Mailchimp. At this point I get a preview on my inbox and then I can
log in and work on editing details and adding an intro before I can schedule
it to be sent out to subscribers the following Monday.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This system ensures a balance of automation and manual editing, allowing me to
focus on delivering (hopefully) quality content, while significantly reducing
the time spent on less differentiated repeated tasks.&lt;/p&gt;
&lt;h2 id=&quot;the-economics-of-fullstack-bulletin&quot;&gt;The Economics of FullStack Bulletin&lt;/h2&gt;
&lt;p&gt;Running a newsletter like FullStack Bulletin comes with its costs.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Money Talks GIF&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;480&quot; height=&quot;270&quot; src=&quot;https://loige.co/_astro/money-talks.CddeEesR_Z1LsLFM.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;At our current scale of around 3,000 subscribers, the Mailchimp subscription
alone costs about $80 per month. Thankfully, given the current design,
everything else comes for free (or very close to free like in the case of the
Step Function and Lambdas execution).&lt;/p&gt;
&lt;p&gt;While this might seem manageable, the true cost becomes apparent when factoring
in the time required for content curation and editing. Spending 1–3 hours every
week on these tasks adds up, pushing the total estimated monthly cost closer to
$500 when considering the value of time and effort.&lt;/p&gt;
&lt;p&gt;Since FullStack Bulletin was never intended as a for-profit venture, I initially
absorbed these costs. However, as the project grew, I decided to accept
sponsorships to help offset these expenses. This decision has been a
game-changer, allowing the newsletter to remain sustainable without compromising
on quality. The newsletter is not breaking even yet, but at least it’s not a
significant loss on my side!&lt;/p&gt;
&lt;p&gt;We’ve been fortunate to collaborate with incredible sponsors, including
&lt;em&gt;PostHog&lt;/em&gt;, &lt;em&gt;Dashlane&lt;/em&gt;, &lt;em&gt;Buttonize&lt;/em&gt;, &lt;em&gt;Packt&lt;/em&gt;, &lt;em&gt;Belka&lt;/em&gt;, &lt;em&gt;MisterDA&lt;/em&gt;, &lt;em&gt;ConfigCat&lt;/em&gt;,
&lt;em&gt;FeedHive&lt;/em&gt;, &lt;em&gt;Upstash&lt;/em&gt;, and &lt;em&gt;Nudge&lt;/em&gt;. Their support has played a vital role in
keeping this project alive, and I am immensely grateful for their partnership.&lt;/p&gt;
&lt;p&gt;If you have a product or service that would resonate with our curated audience
of full-stack developers, sponsorship could be an excellent opportunity. Feel
free to reach out via &lt;a href=&quot;mailto:luciano@fullstackbulletin.com&quot;&gt;email&lt;/a&gt; or
&lt;a href=&quot;https://linktr.ee/loige&quot;&gt;social channels&lt;/a&gt;. I’d be happy to share all the
details, including a slide deck outlining the sponsorship options. Together, we
can continue to bring value to the developer community.&lt;/p&gt;
&lt;h2 id=&quot;looking-ahead&quot;&gt;Looking Ahead&lt;/h2&gt;
&lt;p&gt;There have been moments when I’ve seriously considered shutting down FullStack
Bulletin. Running this newsletter takes a lot of effort, and doing something
consistently over such a long period isn’t easy, especially when balancing a
busy personal and professional schedule. I’ll be the first to admit that
consistency has never been my strongest suit, and keeping up with a weekly
cadence can feel overwhelming at times.&lt;/p&gt;
&lt;p&gt;However, instead of stepping away, I’ve decided to give FullStack Bulletin one
more shot. I believe in its value and the role it plays in the full-stack
developer community. My goal for the coming year is to grow the number of
subscribers and secure more long-term sponsorships to make the project
sustainable. With a larger audience and reliable sponsorship, I could reduce the
financial strain and even consider bringing on someone to help with the
workload.&lt;/p&gt;
&lt;p&gt;Delegating parts of the process—like content curation or editing—could open up
new possibilities, allowing me to focus on other aspects of the newsletter or
even explore ways to expand its reach and impact. This could mark a turning
point for FullStack Bulletin, transforming it into something more structured and
robust while retaining the personal touch that has always set it apart.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Crystal Ball GIF&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;300&quot; height=&quot;233&quot; src=&quot;https://loige.co/_astro/crystal-ball.CwOvjxgu_1XvUjq.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;That said, I haven’t yet finalized any concrete plans. These ideas are still
very much in the brainstorming phase, and I’m open to feedback and suggestions.
If you have thoughts about how FullStack Bulletin could evolve, ways to improve
its content, or strategies for growing its audience, I’d love to hear from you.
Whether it’s a comment, an email, or a private message, your input could help
shape the next chapter of this project.&lt;/p&gt;
&lt;p&gt;For now, I’m excited to see where this renewed commitment will take us and look
forward to continuing this journey with the incredible community of full-stack
developers who have supported FullStack Bulletin over the years.&lt;/p&gt;
&lt;h2 id=&quot;closing-thoughts&quot;&gt;Closing Thoughts&lt;/h2&gt;
&lt;p&gt;FullStack Bulletin has been a labor of love for the past eight years. It’s been
an incredible journey, and I’m excited to see where it goes next. If you haven’t
already, &lt;a href=&quot;https://fullstackbulletin.com&quot;&gt;subscribe today&lt;/a&gt; and let me know what
you think.&lt;/p&gt;
&lt;p&gt;Here’s to Issue 404… and beyond! 🍻&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Cheering with pints GIF&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;360&quot; height=&quot;192&quot; src=&quot;https://loige.co/_astro/cheers.B5nI-430_Zg28h.webp&quot; &gt;&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/404-newsletter-found.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/404-newsletter-found.png" width="1200" height="630"/></media:content><category>life</category><category>serverless</category><category>aws</category><category>lambda</category><category>api</category><category>git</category><author>Luciano Mammino</author><comments>https://loige.co/404-newsletter-found/#comments</comments><enclosure url="https://loige.co/og/404-newsletter-found.png" length="0" type="image/png"/></item><item><title>Debugging AWS API Gateway HTTP with OIDC-JWT authorizers</title><link>https://loige.co/debugging-api-gateway-http-oidc-jwt-authorizer/</link><guid isPermaLink="true">https://loige.co/debugging-api-gateway-http-oidc-jwt-authorizer/</guid><description>Learn how to debug silent failures in AWS API Gateway HTTP when your OIDC provider doesn&apos;t implement the .well-known/openid-configuration endpoint. Enable FailOnWarnings to catch these issues before they break your production deployment.</description><pubDate>Wed, 17 Dec 2025 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently, I was working on an AWS project that required authenticating API requests using OIDC-based JWT tokens. I was using API Gateway HTTP (also known as API Gateway v2) with its built-in JWT authorizer, which seemed like the perfect fit for the job. What should have been a straightforward configuration turned into hours of debugging a mysterious issue: my deployment succeeded, but routes were disappearing from the console and authentication simply wasn’t working.&lt;/p&gt;
&lt;p&gt;This article is a companion to my previous piece on &lt;a href=&quot;/debugging-custom-apigateway-authorizers&quot;&gt;debugging custom API Gateway authorizers&lt;/a&gt;, where I covered how to enable CloudWatch logging for REST API Gateway. This time, we’re tackling a different beast: silent failures in HTTP API Gateway when your OIDC provider doesn’t fully comply with the specification.&lt;/p&gt;
&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;If you’re using AWS API Gateway HTTP with a JWT authorizer and your OIDC provider doesn’t implement the &lt;code&gt;/.well-known/openid-configuration&lt;/code&gt; endpoint, your deployment will appear successful but your authorizer won’t be created and your routes will silently disappear.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; Add &lt;code&gt;FailOnWarnings: true&lt;/code&gt; to your HTTP API resource (e.g., &lt;code&gt;AWS::Serverless::HttpApi&lt;/code&gt; in SAM or &lt;code&gt;AWS::ApiGatewayV2::Api&lt;/code&gt; in CloudFormation). This will make the deployment fail with a clear error message instead of silently breaking your API.&lt;/p&gt;
&lt;p&gt;If you’re in a hurry, jump straight to &lt;a href=&quot;#the-solutions&quot;&gt;the solution&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;api-gateway-http-and-the-built-in-jwt-authorizer&quot;&gt;API Gateway HTTP and the built-in JWT Authorizer&lt;/h2&gt;
&lt;p&gt;AWS offers two main flavors of API Gateway: &lt;strong&gt;REST API (v1)&lt;/strong&gt; and &lt;strong&gt;HTTP API (v2)&lt;/strong&gt;. HTTP API is the newer, lighter, and cheaper option. It’s designed for simpler use cases and offers better performance at a lower cost. One of its nice features is the built-in support for JWT authorizers, which allows you to validate OIDC-based tokens without writing any custom code.&lt;/p&gt;
&lt;p&gt;When you configure a JWT authorizer, you typically provide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An &lt;strong&gt;issuer URL&lt;/strong&gt;: the base URL of your OIDC provider (e.g., &lt;code&gt;https://oidc.loige.co&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;audience&lt;/strong&gt;: the intended recipient of the token (your API)&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;identity source&lt;/strong&gt;: where to find the token (usually &lt;code&gt;$request.header.Authorization&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s what a basic AWS SAM template looks like:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# template.yaml (AWS SAM)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Resources&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;MyApi&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;AWS::Serverless::HttpApi&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Properties&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;StageName&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;v1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Auth&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Authorizers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;MyJwtAuthorizer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;IdentitySource&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;$request.header.Authorization&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;JwtConfiguration&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;issuer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;https://oidc.loige.co&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;audience&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;my-api-audience&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;DefaultAuthorizer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;MyJwtAuthorizer&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;# template.yaml (AWS SAM)Resources:  MyApi:    Type: AWS::Serverless::HttpApi    Properties:      StageName: v1      Auth:        Authorizers:          MyJwtAuthorizer:            IdentitySource: $request.header.Authorization            JwtConfiguration:              issuer: &amp;#x22;https://oidc.loige.co&amp;#x22;              audience:                - &amp;#x22;my-api-audience&amp;#x22;        DefaultAuthorizer: MyJwtAuthorizer&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note on IaC tools&lt;/strong&gt;: Throughout this article, I’ll use AWS SAM for the examples, but the same configuration options are available whether you’re using raw CloudFormation (with &lt;code&gt;AWS::ApiGatewayV2::Api&lt;/code&gt; and &lt;code&gt;AWS::ApiGatewayV2::Authorizer&lt;/code&gt;), AWS CDK, Terraform, Pulumi, or other Infrastructure as Code tools. The key properties like &lt;code&gt;FailOnWarnings&lt;/code&gt; and &lt;code&gt;JwtConfiguration&lt;/code&gt; map to the underlying &lt;a href=&quot;https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis.html&quot;&gt;AWS API Gateway V2 API&lt;/a&gt;, so you’ll find equivalent settings in whatever tool you prefer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is convenient because AWS handles all the heavy lifting: fetching the public keys from your OIDC provider, validating the token signature, checking claims, and so on.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;REST API vs HTTP API&lt;/strong&gt;: If you’re using REST API Gateway (v1), you won’t find this built-in JWT authorizer feature. Instead, you need to implement a custom Lambda authorizer. I’ve built an open-source project called &lt;a href=&quot;https://github.com/lmammino/oidc-authorizer&quot;&gt;&lt;code&gt;oidc-authorizer&lt;/code&gt;&lt;/a&gt; that does exactly this. It’s a high-performance Rust-based Lambda authorizer that handles OIDC token validation. It’s available on &lt;a href=&quot;https://github.com/lmammino/oidc-authorizer&quot;&gt;GitHub&lt;/a&gt; and the &lt;a href=&quot;https://serverlessrepo.aws.amazon.com/applications/eu-west-1/795006566846/oidc-authorizer&quot;&gt;Serverless Application Repository (SAR)&lt;/a&gt;, and it’s highly configurable to support various OIDC providers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;/h2&gt;
&lt;p&gt;The trouble starts when you’re working with an OIDC provider that doesn’t fully implement the OIDC specification. Specifically, the issue arises when the provider doesn’t expose the &lt;code&gt;/.well-known/openid-configuration&lt;/code&gt; endpoint.&lt;/p&gt;
&lt;p&gt;When you configure a JWT authorizer with an issuer URL like &lt;code&gt;https://oidc.loige.co&lt;/code&gt;, AWS assumes it can fetch the OIDC discovery document from &lt;code&gt;https://oidc.loige.co/.well-known/openid-configuration&lt;/code&gt;. This is standard behavior according to the &lt;a href=&quot;https://openid.net/specs/openid-connect-discovery-1_0.html&quot;&gt;OpenID Connect Discovery specification&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How OIDC JWT validation works&lt;/strong&gt;: When validating a JWT token, the authorizer needs to verify that the token’s signature is authentic. To do this, it needs the public key that corresponds to the private key used to sign the token. The OIDC discovery endpoint (&lt;code&gt;/.well-known/openid-configuration&lt;/code&gt;) is a standardized way to find out where to get these public keys. It returns a JSON document that includes (among other things) a &lt;code&gt;jwks_uri&lt;/code&gt; field pointing to the JSON Web Key Set (JWKS) endpoint. The JWKS endpoint returns the actual public keys. Without the discovery endpoint, the authorizer has no way to know where to find the keys needed to validate tokens.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here’s what happens when your OIDC provider doesn’t implement this endpoint:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You deploy your infrastructure (SAM, CloudFormation, CDK, Terraform, etc.)&lt;/li&gt;
&lt;li&gt;The deployment &lt;strong&gt;succeeds&lt;/strong&gt; (no errors!)&lt;/li&gt;
&lt;li&gt;But when you check the API Gateway console, something is wrong:
&lt;ul&gt;
&lt;li&gt;Your routes that use the authorizer are &lt;strong&gt;missing&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;The authorizer itself &lt;strong&gt;doesn’t exist&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;You might notice a subtle error banner in the “Stages” section&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is incredibly frustrating because there’s no obvious indication that anything went wrong. Your deployment completed successfully, your stack shows a green checkmark, but your API is broken.&lt;/p&gt;
&lt;p&gt;I spent a good amount of time scratching my head, checking IAM permissions, reviewing my template syntax, and wondering if I had somehow misconfigured everything. The real culprit was much simpler: the OIDC provider I was integrating with didn’t expose the discovery endpoint.&lt;/p&gt;
&lt;h2 id=&quot;the-solutions&quot;&gt;The Solutions&lt;/h2&gt;
&lt;h3 id=&quot;solution-1-enable-failonwarnings&quot;&gt;Solution 1: Enable FailOnWarnings&lt;/h3&gt;
&lt;p&gt;The first and most important fix is to add &lt;code&gt;FailOnWarnings: true&lt;/code&gt; to your HTTP API resource. Here’s how it looks in an AWS SAM template:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# template.yaml (AWS SAM)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Resources&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;MyApi&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;AWS::Serverless::HttpApi&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Properties&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line highlight mark&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#7cb2df;--1:#8b352d&quot;&gt;FailOnWarnings&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#7cb2df;--1:#6e4c01&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#95b686;--1:#515255;--1fs:italic&quot;&gt;# This is the key!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;StageName&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;v1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Auth&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Authorizers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;MyJwtAuthorizer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;IdentitySource&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;$request.header.Authorization&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;JwtConfiguration&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;issuer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;https://oidc.loige.co&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;audience&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;my-api-audience&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;DefaultAuthorizer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;MyJwtAuthorizer&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;# template.yaml (AWS SAM)Resources:  MyApi:    Type: AWS::Serverless::HttpApi    Properties:      FailOnWarnings: true  # This is the key!      StageName: v1      Auth:        Authorizers:          MyJwtAuthorizer:            IdentitySource: $request.header.Authorization            JwtConfiguration:              issuer: &amp;#x22;https://oidc.loige.co&amp;#x22;              audience:                - &amp;#x22;my-api-audience&amp;#x22;        DefaultAuthorizer: MyJwtAuthorizer&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If you’re using other IaC tools, look for the equivalent property:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CloudFormation&lt;/strong&gt;: &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-apigatewayv2-api.html#cfn-apigatewayv2-api-failonwarnings&quot;&gt;&lt;code&gt;FailOnWarnings&lt;/code&gt;&lt;/a&gt; in the &lt;code&gt;AWS::ApiGatewayV2::Api&lt;/code&gt; resource&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Terraform&lt;/strong&gt;: &lt;a href=&quot;https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/apigatewayv2_api#fail_on_warnings-1&quot;&gt;&lt;code&gt;fail_on_warnings&lt;/code&gt;&lt;/a&gt; in the &lt;code&gt;aws_apigatewayv2_api&lt;/code&gt; resource&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CDK&lt;/strong&gt;: Unfortunately, the high-level &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigatewayv2.HttpApi.html&quot;&gt;&lt;code&gt;HttpApi&lt;/code&gt;&lt;/a&gt; construct doesn’t expose this option directly. You’ll need to use the lower-level &lt;a href=&quot;https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_sam.CfnHttpApi.html&quot;&gt;&lt;code&gt;CfnHttpApi&lt;/code&gt;&lt;/a&gt; construct or use an &lt;a href=&quot;https://repost.aws/knowledge-center/cdk-retrieve-construct-objects&quot;&gt;escape hatch&lt;/a&gt; to access the underlying CloudFormation resource and to set &lt;code&gt;failOnWarnings&lt;/code&gt; on it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With this setting enabled, instead of silently swallowing the error and deploying a broken API, your deployment will fail with a clear error message:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Resource handler returned message: &quot;Warnings found during import:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Unable to create Authorizer &apos;MyJwtAuthorizer&apos;: Caught exception when&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;connecting to https://oidc.loige.co/.well-known/openid-configuration&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;for issuer https://oidc.loige.co. Please try again later.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Resource handler returned message: &amp;#x22;Warnings found during import:Unable to create Authorizer &amp;#x27;MyJwtAuthorizer&amp;#x27;: Caught exception whenconnecting to https://oidc.loige.co/.well-known/openid-configurationfor issuer https://oidc.loige.co. Please try again later.&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This error message tells you exactly what’s wrong: AWS couldn’t connect to the OIDC discovery endpoint. Now you know where to look!&lt;/p&gt;
&lt;p&gt;I strongly recommend &lt;strong&gt;always enabling &lt;code&gt;FailOnWarnings: true&lt;/code&gt;&lt;/strong&gt; on your HTTP API resources. It’s much better to have a deployment fail loudly than to end up with a broken API in production that you might not notice until users start complaining.&lt;/p&gt;
&lt;h3 id=&quot;solution-2-ensure-your-oidc-provider-is-compliant&quot;&gt;Solution 2: Ensure your OIDC provider is compliant&lt;/h3&gt;
&lt;p&gt;Once you know the problem, you can verify it by testing the discovery endpoint manually:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;https://oidc.loige.co/.well-known/openid-configuration&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;curl https://oidc.loige.co/.well-known/openid-configuration&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If this returns a &lt;code&gt;404&lt;/code&gt;, a connection error, or anything other than a valid JSON document with OIDC metadata, you’ve found your culprit.&lt;/p&gt;
&lt;p&gt;The ideal solution is to use an OIDC provider that fully implements the specification. Most major identity providers (Auth0, Okta, Azure AD, AWS Cognito, Keycloak, etc.) do implement the discovery endpoint correctly.&lt;/p&gt;
&lt;p&gt;If you’re working with a provider that doesn’t, you have a few options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Talk to the provider&lt;/strong&gt;: They might be able to add support for the discovery endpoint&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use a different provider&lt;/strong&gt;: If possible, switch to a compliant OIDC provider&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implement a custom Lambda authorizer&lt;/strong&gt;: If you’re stuck with a non-compliant provider, you’ll need to write your own authorizer logic&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;alternative-custom-lambda-authorizer&quot;&gt;Alternative: Custom Lambda Authorizer&lt;/h3&gt;
&lt;p&gt;If your OIDC provider doesn’t support the discovery endpoint and you can’t change providers, your only option is to implement a custom Lambda authorizer. This approach:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gives you full control over the token validation logic&lt;/li&gt;
&lt;li&gt;Allows you to hardcode the JWKS endpoint or public keys&lt;/li&gt;
&lt;li&gt;Works with both REST API and HTTP API Gateway&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The downside is added complexity and cost (Lambda invocations). If you’re using REST API Gateway, check out my &lt;a href=&quot;https://github.com/lmammino/oidc-authorizer&quot;&gt;&lt;code&gt;oidc-authorizer&lt;/code&gt;&lt;/a&gt; project which might serve as inspiration or even a ready-to-use solution. Keep in mind that this particular project is designed for REST API Gateway, but the validation logic could be adapted for HTTP API as well.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;Debugging API Gateway issues can be tricky, especially when deployments succeed but things don’t work as expected. The key takeaways from this article are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Always enable &lt;code&gt;FailOnWarnings: true&lt;/code&gt;&lt;/strong&gt; on your HTTP API Gateway resources. This simple setting can save you hours of debugging by making failures explicit rather than silent.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Understand the OIDC flow&lt;/strong&gt;: The built-in JWT authorizer relies on the OIDC discovery endpoint to find the public keys needed for token validation. If your provider doesn’t implement this endpoint, the authorizer simply won’t work.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Test your OIDC provider&lt;/strong&gt;: Before diving into complex debugging, verify that your OIDC provider exposes the &lt;code&gt;/.well-known/openid-configuration&lt;/code&gt; endpoint correctly.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I hope this article saves you some of the headaches I experienced. If you found it useful or have questions, feel free to reach out in the &lt;a href=&quot;#comments&quot;&gt;comments&lt;/a&gt; below or on &lt;a href=&quot;https://bsky.app/profile/loige.co&quot;&gt;Bluesky&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/debugging-api-gateway-http-oidc-jwt-authorizer.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/debugging-api-gateway-http-oidc-jwt-authorizer.png" width="1200" height="630"/></media:content><category>aws</category><category>serverless</category><category>api-gateway</category><category>jwt</category><category>authentication</category><author>Luciano Mammino</author><comments>https://loige.co/debugging-api-gateway-http-oidc-jwt-authorizer/#comments</comments><enclosure url="https://loige.co/og/debugging-api-gateway-http-oidc-jwt-authorizer.png" length="0" type="image/png"/></item><item><title>How I added Bluesky likes to my Astro blog</title><link>https://loige.co/how-i-added-bluesky-likes-to-my-astro-blog/</link><guid isPermaLink="true">https://loige.co/how-i-added-bluesky-likes-to-my-astro-blog/</guid><description>Learn how I added Bluesky likes and avatars to my Astro blog using the bluesky-likes web components package. No API keys, no server-side code, just a few lines of Astro magic.</description><pubDate>Sun, 08 Mar 2026 19:50:00 GMT</pubDate><content:encoded>&lt;p&gt;This afternoon I was reading &lt;a href=&quot;https://lea.verou.me/blog/2026/external-import-maps-today/&quot;&gt;Lea Verou’s article on external import maps&lt;/a&gt;, a really good read, but that’s not really the point of this article… the point is that, as I scrolled to the bottom of the article, something else caught my eye: a neat little section showing Bluesky likes, complete with avatars of the people who had liked the post.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Screenshot of the Bluesky likes section at the bottom of Lea&amp;amp;#x27;s article, showing the like count and a grid of avatars&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1836&quot; height=&quot;608&quot; src=&quot;https://loige.co/_astro/lea-verou-likes-on-bluesky-screenshot.BIFQjS1V_ZK9EC0.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Then I remembered that I had already seen something like this somewhere else: &lt;a href=&quot;https://whitep4nth3r.com/blog/show-bluesky-likes-on-blog-posts/&quot;&gt;Salma Alam-Naylor’s blog&lt;/a&gt; also had a similar feature showing Bluesky engagement on her posts. Salma’s one has an even more original design:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Screenshot of Salma&amp;amp;#x27;s Bluesky likes section, which has a unique design with a speech bubble and a different avatar layout&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2494&quot; height=&quot;2106&quot; src=&quot;https://loige.co/_astro/salma-alam-naylor-likes-on-bluesky-screenshot.FEWy10wc_Z1AznRH.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;What I really like here is the clever use of CSS filters combined with a background dotted pattern to create this halftone-like effect on the avatars. It’s a great example of how a little bit of CSS creativity can go a long way in making a feature feel unique and integrated with the site’s design. You should seriously go and check the CSS using the browser dev tools, it’s really cool!&lt;/p&gt;
&lt;p&gt;But I digress… again! The point here is that what I thought at this point is… &lt;em&gt;“I’d love to add this Bluesky integration on my blog too!”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here’s how I went from &lt;em&gt;“I want that”&lt;/em&gt; to &lt;em&gt;“it’s live”&lt;/em&gt; in about an hour… admittedly, with a little help from Claude Code.&lt;/p&gt;
&lt;h2 id=&quot;how-it-started&quot;&gt;How it started&lt;/h2&gt;
&lt;p&gt;I admit I was a bit in a rush and needed to complete my next issue of &lt;a href=&quot;https://fullstackbulletin.com&quot;&gt;FullStack Bulletin&lt;/a&gt;, so while I was working on that, I decided to fire up Claude Code and ask it to investigate both Lea’s and Salma’s blogs to see how they implemented the feature and come back to me with a detailed summary. I was hoping for some quick insights that I could then apply to my own blog.&lt;/p&gt;
&lt;p&gt;Once I finished the issue and had a bit more time, I came back to the conversation with Claude Code, and what it found made me realize that this feature can be implemented in a really simple and elegant way using a web component package called &lt;code&gt;bluesky-likes&lt;/code&gt; built by Lea Verou herself.&lt;/p&gt;
&lt;h2 id=&quot;the-bluesky-likes-package&quot;&gt;The &lt;code&gt;bluesky-likes&lt;/code&gt; package&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.npmjs.com/package/bluesky-likes&quot;&gt;&lt;code&gt;bluesky-likes&lt;/code&gt;&lt;/a&gt; package provides two web components that can be easily integrated into any website to display Bluesky likes and the avatars of the people who liked a post, all without needing any server-side code or API keys.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;#x3C;bluesky-likes&gt;&lt;/code&gt;&lt;/strong&gt;: displays the like count&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;#x3C;bluesky-likers&gt;&lt;/code&gt;&lt;/strong&gt;: renders an avatar grid of the people who liked the post&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The simplest possible usage looks like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;index.html&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;https://esm.sh/bluesky-likes/autoload&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;bluesky-likes&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;https://bsky.app/profile/you/post/abc123&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;bluesky-likes&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;people liked this post&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;bluesky-likers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;https://bsky.app/profile/you/post/abc123&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;bluesky-likers&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;script type=&amp;#x22;module&amp;#x22; src=&amp;#x22;https://esm.sh/bluesky-likes/autoload&amp;#x22;&gt;&lt;/script&gt;&lt;bluesky-likes src=&amp;#x22;https://bsky.app/profile/you/post/abc123&amp;#x22;&gt;&lt;/bluesky-likes&gt;people liked this post&lt;bluesky-likers src=&amp;#x22;https://bsky.app/profile/you/post/abc123&amp;#x22;&gt;&lt;/bluesky-likers&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That’s it. You point the &lt;code&gt;src&lt;/code&gt; attribute to a Bluesky post URL and the components do the rest.&lt;/p&gt;
&lt;p&gt;A few things I really like about this package:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tiny&lt;/strong&gt;: ~2 KB gzipped, zero dependencies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No API keys&lt;/strong&gt;: it uses the public Bluesky API (&lt;code&gt;app.bsky.feed.getLikes&lt;/code&gt;) client-side, so there’s no server-side code, no auth tokens, no environment variables, no CORS issues!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Themeable&lt;/strong&gt;: CSS custom properties that penetrate the shadow DOM, so you can match your site’s design.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Autoload script&lt;/strong&gt;: discovers the components in the DOM automatically, no manual &lt;code&gt;customElements.define()&lt;/code&gt; needed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accessible&lt;/strong&gt;: screen reader support and skip links built in.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Under the hood, the component calls the public &lt;code&gt;app.bsky.feed.getLikes&lt;/code&gt; endpoint to fetch liker profiles, then renders the avatars inside a shadow DOM grid. Simple and effective.&lt;/p&gt;
&lt;p&gt;If you want a more detailed peek at what this package does under the hood, you can check out &lt;a href=&quot;https://codepen.io/dmitrysharabin/pen/Jodbyqm&quot;&gt;this Codepen&lt;/a&gt;, which, based on the package’s README, seems to have been the inspiration for the initial implementation. It’s about 50 lines of vanilla JS, and it shows really clearly how you can interact with the Bluesky APIs from a web browser.&lt;/p&gt;
&lt;h2 id=&quot;step-1-adding-the-schema-field&quot;&gt;Step 1: Adding the schema field&lt;/h2&gt;
&lt;p&gt;So the next step was about how to bring this into my blog setup.&lt;/p&gt;
&lt;p&gt;This blog is a static site built with &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt; and uses Zod schemas for content collections. The first thing I needed was a way to associate a Bluesky post URL with each blog post.&lt;/p&gt;
&lt;p&gt;One line change in &lt;code&gt;src/content/config.ts&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;src/content/config.ts&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;posts&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;defineCollection&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;loader&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;glob&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;pattern&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;**/[^_]*.md(x)?&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;base&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;./src/content/posts&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; }),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;schema&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; ({ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;image&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; }) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;z&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;z&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;subtitle&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;z&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;optional&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;nullable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;z&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;optional&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;nullable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;z&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;coerce&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;updated&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;z&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;coerce&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;optional&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;header_img&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;image&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;optional&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;z&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;enum&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;published&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;draft&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;tags&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;z&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;z&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;bluesky_url&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;z&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;optional&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;nullable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// 👈 new!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// ...const posts = defineCollection({  loader: glob({ pattern: &amp;#x27;**/[^_]*.md(x)?&amp;#x27;, base: &amp;#x27;./src/content/posts&amp;#x27; }),  schema: ({ image }) =&gt;    z.object({      title: z.string(),      subtitle: z.string().optional().nullable(),      description: z.string().optional().nullable(),      date: z.coerce.date(),      updated: z.coerce.date().optional(),      header_img: image().optional(),      status: z.enum([&amp;#x27;published&amp;#x27;, &amp;#x27;draft&amp;#x27;]),      tags: z.array(z.string()),      bluesky_url: z.string().url().optional().nullable(), // 👈 new!    }),})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now each post’s frontmatter can optionally include a &lt;code&gt;bluesky_url&lt;/code&gt; field:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;src/content/posts/sample-blog-post/index.md&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;My awesome post&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;slug&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;my-awesome-post&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;2026-03-08T12:00:00.000Z&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;published&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;tags&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;javascript&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;bluesky_url&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;https://bsky.app/profile/loige.co/post/abc123&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;This is the best blog post ever!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;---title: My awesome postslug: my-awesome-postdate: 2026-03-08T12:00:00.000Zstatus: publishedtags:  - javascriptbluesky_url: https://bsky.app/profile/loige.co/post/abc123---This is the best blog post ever!&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;step-2-building-the-component&quot;&gt;Step 2: Building the component&lt;/h2&gt;
&lt;p&gt;Next up, I needed an easy way to include this in my blog post pages. A dedicated Astro component seemed the right abstraction that I could easily bring into the blog post page template. Here’s what the full &lt;code&gt;BlueskyReactions.astro&lt;/code&gt; looks like:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;BlueskyReactions.astro&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;astro&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Props&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;blueskyUrl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;blueskyUrl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Astro&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;props&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;mt-8 pt-8 border-t border-text-100&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;text-text-500 font-bold&quot;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;Bluesky Love&lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;text-text-400 text-sm mt-1&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;bluesky-likes&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;blueskyUrl&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;bluesky-likes&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; awesome folks liked this article&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;on Bluesky&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;mt-4&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;bluesky-likers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;blueskyUrl&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;50&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;bluesky-likers&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;mt-4&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;a&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;blueskyUrl&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;_blank&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;rel&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;noopener noreferrer&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;text-primary-500 hover:text-primary-600 underline text-sm&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;Like or comment on Bluesky&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;bluesky-likes&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;--bluesky-likes-color&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;--color-primary-500&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;bluesky-likers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;--avatar-size&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2.5em&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;--avatar-border&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0.12em&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178&quot;&gt;solid&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;--color-bg-600&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;--avatar-shadow&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0.1em&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0.3em&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;-0.2em&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;rgb&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; / &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0.3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;--more-background&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;--color-primary-500&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;--more-color-text&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;--color-bg-100&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;is:inline&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;https://esm.sh/bluesky-likes/autoload&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;---interface Props {  blueskyUrl: string}const { blueskyUrl } = Astro.props---&lt;div class=&amp;#x22;mt-8 pt-8 border-t border-text-100&amp;#x22;&gt;  &lt;h3 class=&amp;#x22;text-text-500 font-bold&amp;#x22;&gt;Bluesky Love&lt;/h3&gt;  &lt;p class=&amp;#x22;text-text-400 text-sm mt-1&amp;#x22;&gt;    &lt;bluesky-likes src={blueskyUrl}&gt;&lt;/bluesky-likes&gt; awesome folks liked this article    on Bluesky  &lt;/p&gt;  &lt;div class=&amp;#x22;mt-4&amp;#x22;&gt;    &lt;bluesky-likers src={blueskyUrl} max=&amp;#x22;50&amp;#x22;&gt;&lt;/bluesky-likers&gt;  &lt;/div&gt;  &lt;p class=&amp;#x22;mt-4&amp;#x22;&gt;    &lt;a      href={blueskyUrl}      target=&amp;#x22;_blank&amp;#x22;      rel=&amp;#x22;noopener noreferrer&amp;#x22;      class=&amp;#x22;text-primary-500 hover:text-primary-600 underline text-sm&amp;#x22;    &gt;      Like or comment on Bluesky    &lt;/a&gt;  &lt;/p&gt;&lt;/div&gt;&lt;style&gt;  bluesky-likes {    --bluesky-likes-color: var(--color-primary-500);  }  bluesky-likers {    --avatar-size: 2.5em;    --avatar-border: 0.12em solid var(--color-bg-600);    --avatar-shadow: 0 0.1em 0.3em -0.2em rgb(0 0 0 / 0.3);    --more-background: var(--color-primary-500);    --more-color-text: var(--color-bg-100);  }&lt;/style&gt;&lt;script is:inline type=&amp;#x22;module&amp;#x22;&gt;  import &amp;#x27;https://esm.sh/bluesky-likes/autoload&amp;#x27;&lt;/script&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Let me walk through the key parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Props and conditional rendering&lt;/strong&gt;: The component takes a &lt;code&gt;blueskyUrl&lt;/code&gt; prop. As we’ll see in the next step, the page template only renders this component when &lt;code&gt;bluesky_url&lt;/code&gt; is set in the post’s frontmatter. No URL, no section, no script loaded. Progressive enhancement at its finest.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The web components&lt;/strong&gt;: We use both &lt;code&gt;&amp;#x3C;bluesky-likes&gt;&lt;/code&gt; (for the count) and &lt;code&gt;&amp;#x3C;bluesky-likers&gt;&lt;/code&gt; (for the avatar grid), each pointing to the same Bluesky post URL via the &lt;code&gt;src&lt;/code&gt; attribute. The &lt;code&gt;max=&quot;50&quot;&lt;/code&gt; on &lt;code&gt;&amp;#x3C;bluesky-likers&gt;&lt;/code&gt; caps the number of displayed avatars.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The CTA link&lt;/strong&gt;: A simple link inviting readers to &lt;em&gt;“Like or comment on Bluesky”&lt;/em&gt;. Because if you’re going to show likes, you might as well encourage more of them!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;CSS custom properties&lt;/strong&gt;: This is where the theming magic happens. The &lt;code&gt;bluesky-likes&lt;/code&gt; package exposes CSS custom properties that penetrate the shadow DOM, so we can map them to the blog’s existing design tokens. Since my blog uses CSS custom properties for its color scheme (with &lt;code&gt;--color-primary-500&lt;/code&gt;, &lt;code&gt;--color-bg-600&lt;/code&gt;, etc. adapting to dark/light mode), the Bluesky section automatically looks right in both themes. No extra work needed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The &lt;code&gt;esm.sh&lt;/code&gt; import&lt;/strong&gt;: You might notice I’m importing from &lt;code&gt;esm.sh&lt;/code&gt; rather than &lt;code&gt;unpkg&lt;/code&gt;. I originally tried &lt;code&gt;unpkg&lt;/code&gt;, but ran into an issue: &lt;code&gt;unpkg&lt;/code&gt; doesn’t resolve the package’s exports map correctly, which resulted in a 404 on the autoload module. Switching to &lt;code&gt;esm.sh&lt;/code&gt; fixed it immediately. Things don’t always work on the first try!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;is:inline&lt;/code&gt; directive&lt;/strong&gt;: The &lt;code&gt;is:inline&lt;/code&gt; on the &lt;code&gt;&amp;#x3C;script&gt;&lt;/code&gt; tag tells Astro not to bundle or process this script. It gets injected as-is into the HTML. This is important because we want the browser to fetch the module directly from &lt;code&gt;esm.sh&lt;/code&gt; at runtime.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;step-3-wiring-it-into-the-post-page&quot;&gt;Step 3: Wiring it into the post page&lt;/h2&gt;
&lt;p&gt;With the component ready, integrating it into the post page was just three lines in &lt;code&gt;src/pages/[...slug].astro&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;First, the import at the top:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;src/pages/[...slug].astro&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;astro&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;BlueskyReactions&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;../components/BlueskyReactions.astro&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;---// ...import BlueskyReactions from &amp;#x27;../components/BlueskyReactions.astro&amp;#x27;---&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Then, the conditional render in the template:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;src/pages/[...slug].astro&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;astro&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;&amp;#x3C;!-- ... --&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;bluesky_url&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;BlueskyReactions&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;blueskyUrl&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#569CD6&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;post&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;bluesky_url&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;&amp;#x3C;!-- ... --&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;&lt;!-- ... --&gt;{post.data.bluesky_url &amp;#x26;&amp;#x26; (  &lt;BlueskyReactions blueskyUrl={post.data.bluesky_url} /&gt;)}&lt;!-- ... --&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;I placed it between the “Found a typo?” section and the Disqus comments. It felt like the natural spot: after you’ve read the article and before the general comments section. And since it’s conditionally rendered, posts without a &lt;code&gt;bluesky_url&lt;/code&gt; won’t show the section or load the script at all.&lt;/p&gt;
&lt;h2 id=&quot;step-4-finding-all-my-bluesky-posts&quot;&gt;Step 4: Finding all my Bluesky posts&lt;/h2&gt;
&lt;p&gt;OK so the code was done, but I had a problem: I needed to find all the Bluesky post URLs where I had shared links to my blog articles. This turned out to be the most tedious part of the process.&lt;/p&gt;
&lt;p&gt;Thankfully, I discovered the awesome &lt;a href=&quot;https://github.com/mattn/bsky&quot;&gt;&lt;code&gt;bsky&lt;/code&gt; CLI by mattn&lt;/a&gt;, a command-line client for Bluesky (written in Go) that lets you inspect posts and threads as JSON, from the comfort of your CLI.&lt;/p&gt;
&lt;p&gt;The workflow was something like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Search for posts from my profile that mention &lt;code&gt;loige.co&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;For each match, grab the AT Protocol URI (the &lt;code&gt;at://did:.../app.bsky.feed.post/&amp;#x3C;post_id&gt;&lt;/code&gt; format)&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;bsky thread --json &quot;at://...&quot;&lt;/code&gt; to inspect threads and find the root post with the blog link&lt;/li&gt;
&lt;li&gt;Some posts had the link directly, others were threads where the blog URL was in a reply. In those cases, I used the root of the thread&lt;/li&gt;
&lt;li&gt;When multiple posts pointed to the same article, I picked the one with the most engagement&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I ended up using Claude Code to help automate the matching and frontmatter updates across 13 posts. This is exactly the kind of tedious-but-scriptable work where AI tooling shines: &lt;em&gt;“here are 13 Bluesky URLs and 200 blog posts, match them up and update the frontmatter.”&lt;/em&gt; Done in minutes rather than an hour of manual copy-pasting.&lt;/p&gt;
&lt;p&gt;The best bit is that I didn’t need a Bluesky MCP or anything like that. I just told Claude Code to use the &lt;code&gt;bsky&lt;/code&gt; CLI and its built-in &lt;code&gt;--help&lt;/code&gt; command to figure out how to get the data it needed.&lt;/p&gt;
&lt;h2 id=&quot;the-result&quot;&gt;The result&lt;/h2&gt;
&lt;p&gt;If you want to see the feature in action, scroll down to the bottom of this very post! (Well, once I share this on Bluesky and add the URL to the frontmatter, that is.)&lt;/p&gt;
&lt;p&gt;In the meantime, you can check it out on posts like &lt;a href=&quot;/coauthoring-a-book-about-rust-and-lambda/&quot;&gt;I am co-authoring a book about Rust and Lambda&lt;/a&gt; or &lt;a href=&quot;/2025-a-year-in-review/&quot;&gt;2025 - A year in Review&lt;/a&gt;, both of which already have Bluesky likes wired up.&lt;/p&gt;
&lt;p&gt;The section adapts nicely to both dark and light mode, thanks to the CSS custom property mapping. It’s a small detail, but it makes the feature feel native rather than bolted on.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;To sum it up, here’s what it took to add Bluesky likes to this blog:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;1 line&lt;/strong&gt; of schema (&lt;code&gt;bluesky_url&lt;/code&gt; field in the Zod config)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;46 lines&lt;/strong&gt; of component code (&lt;code&gt;BlueskyReactions.astro&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3 lines&lt;/strong&gt; of page integration (import + conditional render)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A big shoutout to &lt;a href=&quot;https://lea.verou.me/&quot;&gt;Lea Verou&lt;/a&gt; for building the excellent &lt;code&gt;bluesky-likes&lt;/code&gt; package and to &lt;a href=&quot;https://whitep4nth3r.com/&quot;&gt;Salma Alam-Naylor&lt;/a&gt; for the original inspiration. The beauty of web components is that they’re framework-agnostic: this same approach would work on Next.js, Hugo, Eleventy, or a plain HTML page.&lt;/p&gt;
&lt;p&gt;If you liked this article, you know what to do: hit that like button on Bluesky and your avatar will show up right below!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/how-i-added-bluesky-likes-to-my-astro-blog.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/how-i-added-bluesky-likes-to-my-astro-blog.png" width="1200" height="630"/></media:content><category>javascript</category><category>astro</category><category>web-components</category><author>Luciano Mammino</author><comments>https://loige.co/how-i-added-bluesky-likes-to-my-astro-blog/#comments</comments><enclosure url="https://loige.co/og/how-i-added-bluesky-likes-to-my-astro-blog.png" length="0" type="image/png"/></item><item><title>Migrating from Gatsby to Astro</title><link>https://loige.co/migrating-from-gatsby-to-astro/</link><guid isPermaLink="true">https://loige.co/migrating-from-gatsby-to-astro/</guid><description>This article discuss the reason why I wanted to migrate this blog from Gatsby to Astro and the process I followed to do it. Plus a bunch of interesting and quirky bugs that I had to troubleshoot and fix along the way.</description><pubDate>Wed, 24 Jan 2024 18:26:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently migrated this blog from &lt;a href=&quot;https://www.gatsbyjs.com/&quot;&gt;Gatsby&lt;/a&gt; to &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt;. Finally, I have to say! I have been meaning to move away from Gatsby for a while, but I never really prioritised this activity until now and all my previous attempts had failed for one reason or another…&lt;/p&gt;
&lt;p&gt;When I published this new version, quite a few people reached out to ask various questions related to this migration. So, in this article I will try to cover my motivations for migrating, the process I followed and some issues and unexpected things I learned along the way. The migration also included a complete redesign of the blog, so I will also touch on that aspect a little bit.&lt;/p&gt;
&lt;h2 id=&quot;the-motivations&quot;&gt;The motivation(s)&lt;/h2&gt;
&lt;p&gt;I have been running this blog for 10 years now. I initially started with a simple &lt;strong&gt;WordPress&lt;/strong&gt; deployment, which I didn’t tolerate for very long. So I quickly moved to &lt;strong&gt;Ghost&lt;/strong&gt;, which I self-hosted on a Digital Ocean VM and ran for a few years. I was quite happy with it, except I wanted a more &lt;em&gt;serverless&lt;/em&gt; low-maintenance solution, so &lt;a href=&quot;/2018-a-year-in-review#static-blog-migration&quot;&gt;I eventually managed to move this blog to Gatsby&lt;/a&gt; and live happily with a fully static and effectively costless solution. This was in 2018, so I have been a Gatsby user for about 6 years!&lt;/p&gt;
&lt;p&gt;So what’s wrong with Gatsby and what was the motivation to move away from it?&lt;/p&gt;
&lt;p&gt;Actually, Gatsby in itself is quite a good product. It has tons of features and plugins. If you like writing React and &lt;a href=&quot;https://mdxjs.com/&quot;&gt;MDX&lt;/a&gt; and shipping your site as a SPA (Single Page Application) nicely cached with a built-in PWA (Progressive Web Apps), Gatsby has it all! It’s also very easy to get started with and it has a very active community publishing a plethora of plugins for the most disparate use cases.&lt;/p&gt;
&lt;p&gt;OK, Luciano, so why the heck did you want to move away from it, then?!&lt;/p&gt;
&lt;p&gt;Good question, I am glad you asked! I think it’s hard to pinpoint one reason; it’s most likely a combination of a few things which are not always Gatsby’s fault…&lt;/p&gt;
&lt;h3 id=&quot;keeping-up-with-the-upgrades&quot;&gt;Keeping up with the upgrades&lt;/h3&gt;
&lt;p&gt;The first releases of Gatsby moved quite quickly and they often required a significant amount of work in migrating to the next version. At some point, I stopped caring about upgrades and I eventually got stuck on an unsupported version. This eventually required me to build my blog with an old and unsupported version of Node.js and to have to rely on outdated and insecure dependencies. Sure, it’s a static blog, so it’s not like I am publishing an interactive application that might have tons of vulnerabilities, but, still, it’s annoying to rely on an outdated build system and have to switch Node version every time I need to work on the blog.&lt;/p&gt;
&lt;p&gt;Fun fact: by looking at the &lt;a href=&quot;https://www.npmjs.com/package/gatsby?activeTab=versions&quot;&gt;number of weekly Gatsby downloads by version&lt;/a&gt;, it looks like I was not alone with this problem!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The number of weekly downloads for different versions of Gatsby. Version 5 (the current major release) is way behind versions 2, 4, and 3 respectively&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1248&quot; height=&quot;864&quot; src=&quot;https://loige.co/_astro/gatsby-downnloads-2024-01-24.CKqUKuIf_2uJSUp.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;As you can see, at the time of writing this, Version 5 (the current major release) is way behind versions 2, 4, and 3 respectively in terms of weekly downloads… Funny to see that the majority of users are still running on version 2! I was stuck on version 3, so maybe I wasn’t doing too bad after all! 🙈&lt;/p&gt;
&lt;h3 id=&quot;complexity&quot;&gt;Complexity&lt;/h3&gt;
&lt;p&gt;This is probably a matter of personal preference, but I feel that Gatsby is a bit of a complex beast. If you need a good reason to justify this statement I actually have 2: &lt;strong&gt;GraphQL&lt;/strong&gt; and &lt;strong&gt;Client-side hydration&lt;/strong&gt;. Let me explain…&lt;/p&gt;
&lt;p&gt;Let’s start with GraphQL.&lt;/p&gt;
&lt;p&gt;When you build static websites, you generally need to have some kind of way to load data from one or more sources. After all, the main task of a static site generator is to take data and templates as input and produce web assets (HTML, CSS, JavaScript, Images, etc) as output.&lt;/p&gt;
&lt;p&gt;Gatsby abstracts the concept of data loading with GraphQL. This is a very powerful abstraction that allows you to fetch data with extreme precision. Many frontend developers have gotten accustomed to this way of retrieving data so it makes sense for Gatsby to adopt this abstraction.&lt;/p&gt;
&lt;p&gt;On the other hand, it feels like an unnecessary complexity when dealing with static websites where most often you are loading data from relatively simple markdown, MDX or Yaml files. Most often you just want to load all the data (you’ll need to generate all the pages anyway) and you still have to think in terms of GraphQL queries.&lt;/p&gt;
&lt;p&gt;I did enjoy it at first (maybe because of the novelty of GraphQL), but I got eventually fed up with it!&lt;/p&gt;
&lt;p&gt;What about Client-side hydration? Isn’t that a good thing?!&lt;/p&gt;
&lt;p&gt;Giving you an &lt;a href=&quot;https://www.gatsbyjs.com/docs/conceptual/overview-of-the-gatsby-build-process/&quot;&gt;overview of the Gatsby build process&lt;/a&gt; is a bit out of the scope of this article, so I am going to focus only on what the final output looks like.&lt;/p&gt;
&lt;p&gt;Gatsby produces highly optimised static websites that are built as a Single Page React Application with Server Side rendering and Client Side hydration. This means that the initial page load is very fast and the subsequent navigation is also very fast because the pages are already rendered and only need to be hydrated with the data.&lt;/p&gt;
&lt;p&gt;This is all very good and dandy! Many would argue that this is the state of the art of frontend development and I don’t necessarily disagree with that. However, it’s not a simple system and it comes with lots of complexity and sometimes can lead to very nasty and unexpected bugs that are very hard to understand and fix.&lt;/p&gt;
&lt;p&gt;One particular bug that I had was on my &lt;a href=&quot;/speaking&quot;&gt;speaking page&lt;/a&gt; where I have a list of past and future talks. This list is populated from a folder containing files ordered by date. Very naively, I used to separate future and past talks by comparing the event date with the current date. The problem here is that the current date is not &lt;em&gt;always&lt;/em&gt; the same on the server and on the client! When you build a new version of the website everything looks fine: your build date and the client date will be aligned for the rest of the day… from the next day on, though, the dates will start to diverge.&lt;/p&gt;
&lt;p&gt;In my case, this messed up the hydration phase, which couldn’t perfectly reconcile 2 lists that could effectively be different between the statically rendered version page and the client-side rendered one. If you opened the page, everything looks good, but sometimes you would have links being mixed up and pointing to the wrong slide deck or video. Very nasty!&lt;/p&gt;
&lt;p&gt;Of course there are solution to this problem and the bug is probably on me, but it took me a while to even discover and understand this issue. For this particular use case, I’d rather give up on some hardcore optimization and take a simpler system that is easier to work with and gives more predictable results.&lt;/p&gt;
&lt;h3 id=&quot;shiny-object-syndrome--easter-eggs&quot;&gt;Shiny-object syndrome &amp;#x26; Easter Eggs&lt;/h3&gt;
&lt;p&gt;The last reason for switching to something else is because in tech we are guilty of always chasing the last cool thing! Astro is all the rage right now and therefore I was really curious to try it and see what it would look like to re-develop my blog with it. Guilty as charged!&lt;/p&gt;
&lt;p&gt;I will also include here the fact that I took this re-implementation opportunity also as an opportunity to re-design the aestetich of the blog.&lt;/p&gt;
&lt;p&gt;I wanted to make the blog more personal for a while. I liked the previous look, but I felt I wanted something with more character that might convey a bit more of my passion for tech and the fact that I don’t like to take myself too seriously. Work can and should be fun, after all!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;My new home page header picture&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1200&quot; height=&quot;630&quot; src=&quot;https://loige.co/_astro/loige-co.DzJsYuFc_10rwiI.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;This is my new home page header. It has some scroll-based animation, which is only one of the few easter eggs I put here and there to give more character to the website.&lt;/p&gt;
&lt;p&gt;Can you find them all? I’ll give you a hint, have you bumped into the &lt;a href=&quot;/404&quot;&gt;404 page&lt;/a&gt; already?&lt;/p&gt;
&lt;h2 id=&quot;astro-vs-eleventy&quot;&gt;Astro vs Eleventy&lt;/h2&gt;
&lt;p&gt;So now that you have an overview of my motivations, let’s talk about what else I have considered for this migration during the last couple of years.&lt;/p&gt;
&lt;h3 id=&quot;eleventy&quot;&gt;Eleventy&lt;/h3&gt;
&lt;p&gt;&lt;img alt=&quot;The eleventy logo with its mascot: a flying raccoon with a red balloon&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;842&quot; height=&quot;404&quot; src=&quot;https://loige.co/_astro/11ty.pTu-Cj2x_U7jnq.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;I am a big fan of &lt;a href=&quot;https://www.11ty.dev&quot;&gt;Eleventy&lt;/a&gt;. I truly think &lt;a href=&quot;https://www.zachleat.com/&quot;&gt;Zach&lt;/a&gt; and the open-source community behind Eleventy have done a fantastic job at building something simple and yet extremely powerful. If you have never seen Eleventy in action, I candidly recommend you to check out my blog post called &lt;a href=&quot;https://dev.to/loige/getting-started-with-eleventy-in-11-minutes-496j&quot;&gt;Getting started with Eleventy in 11 minutes&lt;/a&gt; which, even though is not super up-to-date, should still convey how easy it is to get started and be productive with Eleventy.&lt;/p&gt;
&lt;p&gt;Another thing that I really like about Eleventy is that it tries to stay as close as possible to the web standards. It doesn’t try to reinvent the wheel or do magic things for you. In a way, it’s very bare-bone and truthful to the principles of static site generators: data and templates in, static assets out. Every page is a regular HTML page, there is no &lt;em&gt;auto-magic™️&lt;/em&gt; SPA and PWA generation. If you want these things, you can still have them, but you have to build them yourself or use optional third-party plugins.&lt;/p&gt;
&lt;p&gt;I built quite a few websites with Eleventy (e.g. &lt;a href=&quot;https://www.nodejsdesignpatterns.com/&quot;&gt;Node.js Design Pattens&lt;/a&gt; one and the &lt;a href=&quot;https://awsbites.com/&quot;&gt;AWS Bites Podcast&lt;/a&gt; one) and I am generally very happy with it! So why didn’t I use it for this blog?&lt;/p&gt;
&lt;p&gt;There are probably 2 main reasons. The first one is easy: I already mentioned the shiny-object syndrome… I simply wanted to play with something new and shiny!&lt;/p&gt;
&lt;p&gt;The second one is a bit more subtle and specific to this use case.&lt;/p&gt;
&lt;p&gt;Eleventy supports quite a &lt;a href=&quot;https://www.11ty.dev/docs/languages/&quot;&gt;wide variety of templating languages&lt;/a&gt;, which is fantastic. Unfortunately among all of these templates there isn’t an option that offers something very close to React/JSX in terms of syntax and component-first mindset. Coming from Gatsby, I had a lot of existing JSX code that I wanted to re-use and I didn’t want to have to re-write it all in a different templating language. Even if I wanted to put the effort into migrating all my pre-existing templates to something like &lt;a href=&quot;https://mozilla.github.io/nunjucks/&quot;&gt;Nunjucks&lt;/a&gt;, these &lt;em&gt;more traditional&lt;/em&gt; templating languages don’t follow a &lt;em&gt;“component-first”&lt;/em&gt; approach, which is something I like about React and that I wanted to keep for this blog.&lt;/p&gt;
&lt;p&gt;Note that recent developments in Eleventy have brought &lt;a href=&quot;https://www.11ty.dev/docs/languages/webc/&quot;&gt;WebC&lt;/a&gt;, which is a new templating language that supports both &lt;em&gt;component-first&lt;/em&gt; templating but also both server-side and client-side rendering. I haven’t tried it yet, but this seems an ideal solution if you don’t care much about JSX and are looking for something closer to web standards.&lt;/p&gt;
&lt;h3 id=&quot;astro&quot;&gt;Astro&lt;/h3&gt;
&lt;p&gt;Let’s talk about Astro now!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A screenshot of the Astro website Header says &amp;quot;The web framework for content-driven websites. Astro powers the world&amp;amp;#x27;s fastest websites, client-side web apps, dynamic API endpoints, and everything in-between&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;842&quot; height=&quot;404&quot; src=&quot;https://loige.co/_astro/astro.Y1cmNdR7_Z4XyXv.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;When Astro came out about 3 years ago, it seemed like a very promising tool. The main proposition was to abandon the idea of SPAs and go back to a more traditional approach of building websites with HTML, CSS and JavaScript. But at the same time it didn’t give up on the idea of using powerful client-side libraries such as React, Vue, or Svelte. You can even mix and match these libraries and use them together in the same project if you really want to…&lt;/p&gt;
&lt;p&gt;This is achieved through a concept that Astro describes as &lt;a href=&quot;https://docs.astro.build/en/concepts/islands/&quot;&gt;&lt;em&gt;The islands’ architecture&lt;/em&gt;&lt;/a&gt;. Note that this architecture was proposed before Astro, specifically by &lt;a href=&quot;https://front-end.social/@ksylor&quot;&gt;Katie Sylor-Miller&lt;/a&gt; and later by &lt;a href=&quot;https://twitter.com/_developit&quot;&gt;Jason Miller&lt;/a&gt; in a &lt;a href=&quot;https://jasonformat.com/islands-architecture/&quot;&gt;detailed blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The gist of it is very simple and, in a way, quite traditional: you ship HTML pages. Each page is a standalone HTML page that can contain “Interactive areas” (islands) that have client-side logic written in your framework of choice (or even vanilla JavaScript). Beautiful… Isn’t that what the web was supposed to be in the first place?!&lt;/p&gt;
&lt;p&gt;Another thing that, IMHO, Astro got right is the &lt;a href=&quot;https://docs.astro.build/en/core-concepts/astro-syntax/&quot;&gt;Astro templating language&lt;/a&gt;. It’s effectively a JSX syntax with a frontmatter and it allows you to write components in a very similar way to React. This was a big selling point for me, as I mentioned before.&lt;/p&gt;
&lt;p&gt;Just to give you an idea, a simple Astro component might look like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;Hero.astro&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;astro&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;DEFAULT_TITLE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;DEFAULT_DESCRIPTION&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;./defaults.ts&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Props&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;tags&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Astro&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;props&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;DEFAULT_TILE&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;DEFAULT_DESCRIPTION&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;tags&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;tags&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;tag&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;tag&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;---import { DEFAULT_TITLE, DEFAULT_DESCRIPTION } from &amp;#x27;./defaults.ts&amp;#x27;type Props = {  title?: string  description?: string  tags?: string[]}const props = Astro.props---&lt;div&gt;  &lt;h1&gt;{props.title || DEFAULT_TILE}&lt;/h1&gt;  &lt;p&gt;{props.description || DEFAULT_DESCRIPTION}&lt;/p&gt;  {    props.tags &amp;#x26;&amp;#x26; (      &lt;ul&gt;        {props.tags.map((tag) =&gt; (          &lt;li&gt;{tag}&lt;/li&gt;        ))}      &lt;/ul&gt;    )  }&lt;/div&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We have 2 distinct parts here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The frontmatter&lt;/strong&gt;: this is the part between the &lt;code&gt;---&lt;/code&gt; barriers and it’s used to define logic to load the data needed by the component and to describe the &lt;em&gt;props&lt;/em&gt; accepted by the component. It can contain regular JavaScript code or, as I am doing here, even TypeScript!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The template&lt;/strong&gt;: this is the part after the frontmatter and it’s the actual template of the component. It’s written in a JSX-like syntax and it’s very similar to what you would write in React. The only difference is that this code is only going to run server-side at render time, so you don’t have any lifetime hook, event-handling mechanisms or other client-side logic here.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Astro components are composable (just like React components) and you can use them to build pages. For example, a page could easily reuse the &lt;code&gt;Hero&lt;/code&gt; component we defined before:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;astro&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Hero&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;./Hero.astro&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Hero&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;some title&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;some description&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;tags&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;tag1&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;tag2&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;tag3&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;/&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;---import Hero from &amp;#x27;./Hero.astro&amp;#x27;---&lt;html&gt;  &lt;body&gt;    &lt;Hero      title=&amp;#x22;some title&amp;#x22;      description=&amp;#x22;some description&amp;#x22;      tags={[&amp;#x27;tag1&amp;#x27;, &amp;#x27;tag2&amp;#x27;, &amp;#x27;tag3&amp;#x27;]}    /&gt;  &lt;/body&gt;&lt;/html&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Very cool and just the kind of stuff I was looking for to make it easier to migrate parts of my React components from the Gatsby version.&lt;/p&gt;
&lt;h2 id=&quot;first-impressions-with-astro-pre-100&quot;&gt;First impressions with Astro (pre 1.0.0)&lt;/h2&gt;
&lt;p&gt;The first time I attempted a migration of this blog to Astro was about 2 years ago (pre-Astro 1.0.0). I was very excited about the project and I wanted to give it a try. I was also very curious to see how it would feel to migrate my React components to Astro components.&lt;/p&gt;
&lt;p&gt;The initial phases of starting the project and migrating a few components was quite smooth but then I started to stumble on a few limitations.&lt;/p&gt;
&lt;p&gt;The first big limitation was the file-system-based routing mechanism. If you want to generate a file for the path &lt;code&gt;/a/b/c.html&lt;/code&gt; you &lt;em&gt;must&lt;/em&gt; create a component with a very specific path in the project: &lt;code&gt;src/pages/a/b/c.astro&lt;/code&gt;. This is very different from Gatsby and Eleventy, where you can define a custom path for each page. There were ways to work around this limitation, but they were not very elegant and I didn’t want to have to deal with them. I also didn’t want to change the URLs of my blog just to make Astro happy!&lt;/p&gt;
&lt;p&gt;The second limitation I found was around referencing images from markdown content. In my Gatsby blog I structured my blog posts by creating a dedicated folder per blog post. Every folder would look more or less like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;2024-01-24-article_title/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;├── index.md&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;├── post-header-picture.jpg&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;├── pic1.jpg&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;├── pic2.gif&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;└── pic3.png&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;2024-01-24-article_title/├── index.md├── post-header-picture.jpg├── pic1.jpg├── pic2.gif└── pic3.png&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;index.md&lt;/code&gt; is the actual article in markdown format. All the other files are images that I would reference from the markdown file using the following syntax:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;markdown&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;![&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#3360C1&quot;&gt;Description of picture 1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--1:#A626A4&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--0td:underline&quot;&gt;./pic1.jpg&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;![Description of picture 1](./pic1.jpg)&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Which means “Include the image relative to the current &lt;code&gt;index.md&lt;/code&gt; called &lt;code&gt;pic1.jpg&lt;/code&gt;”.&lt;/p&gt;
&lt;p&gt;Well, this simply didn’t work in Astro (pre-1.0.0). The way images were handled was very different and (by default) it was forcing you to put all your images in a &lt;em&gt;potentially messy&lt;/em&gt; shared folder. I tried to change this behaviour by creating custom plugins and I was partially successful at it, but, at the end of the day, it felt like a brittle hack than something that would have worked longer term.&lt;/p&gt;
&lt;p&gt;Similarly, something I would do for every post is to have a representative image that I put at the top of the page and in the social previews. I referenced these images in the frontmatter of the markdown file like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;markdown&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;header_img&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;./post-header-picture.jpg&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;---&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;---header_img: ./post-header-picture.jpg---&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In gatsby this syntax was supported out of the box and the build phase would automatically process the image and make sure it is somehow optimized and included in the final build.&lt;/p&gt;
&lt;p&gt;Well, another thing that Astro didn’t support out of the box…&lt;/p&gt;
&lt;p&gt;And this was the last drop that led me to give up on my first attempt at migrating to Astro! 👎&lt;/p&gt;
&lt;p&gt;I still saw potential in it, but it didn’t feel like a mature enough solution for my needs… And that lead me to stop my attempts at moving away from Gatsby for a while…&lt;/p&gt;
&lt;h2 id=&quot;second-attempt-astro-4&quot;&gt;Second attempt (Astro 4)&lt;/h2&gt;
&lt;p&gt;During the first week of 2024, somehow my enthusiasm for revamping my blog was rekindled and, since I was hearing a lot of hype around Astro, I decided to give it another try. Funny to see there was already a version 4 (after slightly more than 1 year from v1.0.0). That gave a bit of hope that the project was now in a much more mature state.&lt;/p&gt;
&lt;p&gt;I wasn’t disappointed.&lt;/p&gt;
&lt;p&gt;I was very happy to see that the project had evolved quite a bit since my first attempt. All the features I was missing were added and all the stumbling blocks I found were fixed. New exciting features were added (e.g. &lt;a href=&quot;https://docs.astro.build/en/guides/content-collections/&quot;&gt;Astro content collections&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The best thing ever was discovering a tiny easter egg. Now the default local URL when you run the development server would be:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;http://localhost:4321&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;http://localhost:4321&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;4… 3… 2… 1… GO 🚀&lt;/p&gt;
&lt;p&gt;How appropriate for a product called &lt;em&gt;astro&lt;/em&gt;! I can only say &lt;em&gt;well done&lt;/em&gt; to the team! 👏&lt;/p&gt;
&lt;p&gt;I was confident I could do this migration successfully this time!&lt;/p&gt;
&lt;h2 id=&quot;migration&quot;&gt;Migration&lt;/h2&gt;
&lt;p&gt;Once I was able to render my blog posts smoothly without having to change much of the existing code, all the previous blockers were gone.&lt;/p&gt;
&lt;p&gt;So the process for migration was methodical, but overall quite simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I made a list of all the existing pages and components that I had in the old Gatsby version. Then I started to port them one by one to Astro.&lt;/li&gt;
&lt;li&gt;In the process of porting the various pages I also took the opportunity to re-design them. This meant that I also needed to invest a bit of time in coming up with a consistent theme, a colour palette and a few other things. I am not a designer, so this was probably the most time-consuming part of the migration, where I spent a lot of time looking at resources, ispirations and trying things out until I was happy with the result.&lt;/li&gt;
&lt;li&gt;I also needed to make sure to generate all the other &lt;em&gt;less visual&lt;/em&gt; kinds of files you need to have in a blog (or website in general): the RSS feed, the sitemap, the &lt;code&gt;robots.txt&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;By comparing the sitemaps I could make sure I was migrating all the existing pages without forgetting anything. I respected &lt;em&gt;almost&lt;/em&gt; all the URLs but I wanted to make a few small changes here and there and thankfully, Astro supports the generation of &lt;a href=&quot;https://docs.astro.build/en/core-concepts/routing/#redirects&quot;&gt;Redirect Pages&lt;/a&gt; with a very simple piece of configuration.&lt;/li&gt;
&lt;li&gt;I had to make sure I was also populating all the headers and SEO metatags correctly. Here, again, I went on comparing the old blog and making sure I was generating very similar markup for all the new pages.&lt;/li&gt;
&lt;li&gt;I had to generate the social preview images for every blog post. I ended up doing that using &lt;a href=&quot;https://docs.astro.build/en/core-concepts/routing/#static-routes&quot;&gt;Server-Side Generated Dynamic Routes (SSG)&lt;/a&gt; and &lt;a href=&quot;https://www.npmjs.com/package/canvas&quot;&gt;&lt;code&gt;node-canvas&lt;/code&gt;&lt;/a&gt;. This is something pretty cool that I might write about in a future article. Meanwhile, if you are curious, &lt;a href=&quot;https://github.com/lmammino/loige.co/blob/bf134d555ff66301844e5a0f35e648b4f9154ba5/src/pages/og/%5B...slug%5D.png.ts&quot;&gt;you can check out the code&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Finally, I had to update my GitHub Actions workflow to make sure I was building and deploying the new version of the blog correctly. Again, this is probably worth its own article. Meanwhile, &lt;a href=&quot;https://github.com/lmammino/loige.co/blob/6b5d4de41979e5125e884a0e87442f7faeda2fe8/.github/workflows/deploy.yml&quot;&gt;you can check out the code&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All that work led to a &lt;a href=&quot;https://github.com/lmammino/loige.co/pull/142&quot;&gt;huge pull request&lt;/a&gt;, but I was quite happy with the result and decided to ship it!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A ship sailing in the sea with the text &amp;quot;I see it. I ship it&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;350&quot; height=&quot;196&quot; src=&quot;https://loige.co/_astro/ship-it.ClIO14tJ_62Ux0.webp&quot; &gt;&lt;/p&gt;
&lt;h2 id=&quot;post-migration-issues&quot;&gt;Post-migration issues&lt;/h2&gt;
&lt;p&gt;And that’s where the fun part begins!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A bee and a ladybug having fun&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;500&quot; height=&quot;500&quot; src=&quot;https://loige.co/_astro/bugs-everywhere.C-o9Mqn6_Z216L9w.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;BUGS! BUGS EVERYWHERE!&lt;/strong&gt; 🐞🐝&lt;/p&gt;
&lt;h3 id=&quot;missing-text-on-android&quot;&gt;Missing text on Android&lt;/h3&gt;
&lt;p&gt;Very shortly after I posted on social media about the new blog, a couple of folks started to report that they couldn’t see any text on the blog when they opened it on their Android phones. 🤯 SHOCKING!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;2 screenshot of mobile fonts showcasing this website with no font loaded (no text, all whithe backgrounds and only some images)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;546&quot; height=&quot;600&quot; src=&quot;https://loige.co/_astro/no-fonts-on-android-bug.DE1L28bM_Z2pfPAa.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;I opened my mobile phone and saw the same problem. How I didn’t notice that earlier?! I was also quite puzzled by this! There was an obvious issue with loading some custom font, but why didn’t it fallback to a default system font (or to the next font in my font stack)?!&lt;/p&gt;
&lt;p&gt;After some mad &lt;em&gt;googling&lt;/em&gt; I stumbled into this blog post: &lt;a href=&quot;https://aryan-mittal.medium.com/custom-woff-font-not-working-on-android-heres-why-cf6e81e14f4c&quot;&gt;Custom WOFF font not working on Android? Here’s why&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I was using a &lt;strong&gt;WOFF&lt;/strong&gt; file format for the custom font I decided to use: &lt;a href=&quot;https://fonts.google.com/specimen/Atkinson+Hyperlegible&quot;&gt;Atkinson Hyperlegible&lt;/a&gt;. Switching the file format to &lt;strong&gt;WOFF2&lt;/strong&gt; somehow seems to have solved the issues with all the platforms I could test with.&lt;/p&gt;
&lt;p&gt;If you still see weird font issues, please let me know! Even though, if you have font issues, I am not sure how you’ll be able to read this article… 🤔&lt;/p&gt;
&lt;h3 id=&quot;poor-lcp-score-on-lighthouse&quot;&gt;Poor LCP score on Lighthouse&lt;/h3&gt;
&lt;p&gt;This one was not really a bug, but more of a performance issue. When I ran a Lighthouse audit on the new blog, I was quite disappointed to see that the LCP (&lt;a href=&quot;https://web.dev/articles/optimize-lcp&quot;&gt;Largest Contentful Paint&lt;/a&gt;) score was quite low on mobile. This is the metric that measures how long it takes for the main content of the page to be rendered. It’s a very important metric for SEO and it’s also a good indicator of how fast your page is perceived by the user.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A screenshot of a Google Lighthouse run showing the following scores. 87 performance, 96 accessibility, 100 best practices, 98 SEO&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;900&quot; height=&quot;839&quot; src=&quot;https://loige.co/_astro/low-lcp-loige-co.CRS8hjW4_ZcFfBL.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;The reason why this was happening was… well my picture! The one I was using there wasn’t particularly optimized and much bigger than it needed to be.&lt;/p&gt;
&lt;p&gt;To fix this problem I did a few things.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I used the Astro &lt;a href=&quot;https://docs.astro.build/en/guides/images/#picture-&quot;&gt;&lt;code&gt;Picture&lt;/code&gt; component&lt;/a&gt; which performs build time optimization of the image producing multiple versions of the same image with different sizes and formats (including modern ones like &lt;em&gt;WEBP&lt;/em&gt; and &lt;em&gt;AVIF&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;I also created a &lt;em&gt;pixelated&lt;/em&gt; placeholder that can be very small in file size and load very fast.&lt;/li&gt;
&lt;li&gt;I converted this pixelated image to &lt;em&gt;WEBP&lt;/em&gt; (~13kb once Base64 encoded) and &lt;em&gt;AVIF&lt;/em&gt; (~8kb once Base64 encoded). Since these files are so small, I can include them straight away in the generated HTML using the inline &lt;code&gt;data:image/&amp;#x3C;FORMAT&gt;;base64,...&lt;/code&gt;. This should reduce the number of network requests, because the image content is already available in the HTML page.&lt;/li&gt;
&lt;li&gt;Removed the &lt;code&gt;lazy&lt;/code&gt; and &lt;code&gt;defer&lt;/code&gt; attributes from the image tag. This was the most counter-intuitive change. I thought that using these attributes would have helped with the LCP score, but since the image is the main piece of content that users will see on the home page, you actually want to load it as soon as possible and not defer it!&lt;/li&gt;
&lt;li&gt;Added a tiny bit of JavaScript that will load the full image in the background and replace the placeholder image once it’s loaded.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;The pixelated profile picture loaded as a placeholder&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;480&quot; height=&quot;480&quot; src=&quot;https://loige.co/_astro/loige-co-hero_placeholder_480.C64ROeFx_19dNLe.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Above you can see the pixelated placeholder image. I think I look cool in pixel art! 😎&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;I am not a frontend performance expert, but after all these changes this is the new Lighthouse score and I am quite happy with it:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A screenshot of a Google Lighthouse run showing the following scores. 99 performance, 95 accessibility, 100 best practices, 98 SEO&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;900&quot; height=&quot;839&quot; src=&quot;https://loige.co/_astro/better-lcp-loige-co.DrTPXVbx_1V5S39.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;If you have any suggestions on how to improve this further, please let me know!&lt;/p&gt;
&lt;p&gt;I haven’t tested other pages other than the &lt;a href=&quot;/&quot;&gt;home page&lt;/a&gt; against Lighthouse, so this is something for my TODO list.&lt;/p&gt;
&lt;h3 id=&quot;cached-website-on-mobile-due-to-old-gatsby-pwa&quot;&gt;Cached website on mobile due to old Gatsby PWA&lt;/h3&gt;
&lt;p&gt;When I checked the website on an old mobile phone, I was still getting the old website! 🤯 I tried a few refresh and I couldn’t get the new website to show up! I did eventually open an incognito window and that showed the new website correctly. So, clearly a caching issue, but it took me a while to realise that it was the old Gatsby PWA application that was still running on my mobile and having a cached version of most pages on the website!&lt;/p&gt;
&lt;p&gt;The new version of the website doesn’t have PWA support, so the question was: &lt;em&gt;how do I get rid of the old PWA?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;After some research, I ended up finding a solution that works in 2 steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Have a script in the new Astro website that registers a new service worker (with the same URL as the old one).&lt;/li&gt;
&lt;li&gt;The new service worker doesn’t do anything useful other than forcing a refresh of all the open pages.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is the code for step 1:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;serviceWorker&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;navigator&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;navigator&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;serviceWorker&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;register&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/sw.js&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;reg&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;reg&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;active&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;reg&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;_err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {}) &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ignore errors&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;if (&amp;#x27;serviceWorker&amp;#x27; in navigator) {  navigator.serviceWorker    .register(&amp;#x27;/sw.js&amp;#x27;)    .then((reg) =&gt; {      if (reg.active) {        reg.update()      }    })    .catch((_err) =&gt; {}) // ignore errors}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And this is the dummy Service Worker for step 2:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;addEventListener&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;install&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, () &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Skip over the &quot;waiting&quot; lifecycle state, to ensure that our&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// new service worker is activated immediately, even if there&apos;s&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// another tab open controlled by our older service worker code.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;skipWaiting&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;addEventListener&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;activate&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, () &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Optional: Get a list of all the current open windows/tabs under&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// our service worker&apos;s control, and force them to reload.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// This can &quot;unbreak&quot; any open windows/tabs as soon as the new&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// service worker activates, rather than users having to manually reload.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;clients&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;matchAll&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;window&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;windowClients&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;windowClient&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;windowClients&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;windowClient&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;navigate&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;windowClient&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;self.addEventListener(&amp;#x27;install&amp;#x27;, () =&gt; {  // Skip over the &amp;#x22;waiting&amp;#x22; lifecycle state, to ensure that our  // new service worker is activated immediately, even if there&amp;#x27;s  // another tab open controlled by our older service worker code.  self.skipWaiting()})self.addEventListener(&amp;#x27;activate&amp;#x27;, () =&gt; {  // Optional: Get a list of all the current open windows/tabs under  // our service worker&amp;#x27;s control, and force them to reload.  // This can &amp;#x22;unbreak&amp;#x22; any open windows/tabs as soon as the new  // service worker activates, rather than users having to manually reload.  self.clients    .matchAll({      type: &amp;#x27;window&amp;#x27;,    })    .then((windowClients) =&gt; {      for (const windowClient of windowClients) {        windowClient.navigate(windowClient.url)      }    })})&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This seems to have been enough to invalidate the cache and show the new website from my old mobile, so the few people who had visited my website before should now be able to see the new version of it consistently… Or at least that’s what I can tell based on my experiments. If you still see the old version, please let me know!&lt;/p&gt;
&lt;p&gt;These were some of the useful sources I used to come up with this solution:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/NekR/self-destroying-sw&quot;&gt;Self-destroying ServiceWorker&lt;/a&gt; (a 7-year-old repo with no updates!)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/service-worker-mindset&quot;&gt;Service worker mindset&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/workbox/remove-buggy-service-workers/&quot;&gt;Removing buggy service workers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;keyframes-tree-shaking-issues&quot;&gt;&lt;code&gt;@keyframes&lt;/code&gt; tree-shaking issues&lt;/h3&gt;
&lt;p&gt;Ok, To discuss this issue I need to give away one of my easter eggs… 🐣 so &lt;strong&gt;SPOILERS AHEAD&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Now, look at this bad boy:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;An animation of a clickable Super Mario that says Mario things such as &amp;quot;Okey Dokey&amp;quot; every time you click it&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;361&quot; height=&quot;218&quot; src=&quot;https://loige.co/_astro/mario-easter-egg-on-loige-co.D_051Bku_1wyIEI.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;You can find this one on the &lt;a href=&quot;/about&quot;&gt;about page&lt;/a&gt;. Don’t click it too much though!&lt;/p&gt;
&lt;p&gt;What was the problem here?! Well, this beautiful animation was working locally, but it was not working in production, which made me very disappointed because I am very proud of this one! 🤨&lt;/p&gt;
&lt;p&gt;When I was clicking Mario in production, I wouldn’t see any squishy animation nor the floating bubbles with the messages…&lt;/p&gt;
&lt;p&gt;This was another one that took me a while to understand enough so that I could try to fix it. There are at least 2 contributing factors here.&lt;/p&gt;
&lt;p&gt;The first one is that I am implementing these animations using some custom CSS &lt;code&gt;@keyframes&lt;/code&gt; rules. For example this is how the squishy animatin looks like:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;@keyframes&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;squish&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;0% {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;transform&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;scaleY&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;10% {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;transform&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;scaleY&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0.75&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;50% {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;transform&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;scaleY&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1.25&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;100% {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;transform&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;scaleY&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;@keyframes squish {  0% {    transform: scaleY(1);  }  10% {    transform: scaleY(0.75);  }  50% {    transform: scaleY(1.25);  }  100% {    transform: scaleY(1);  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This animation is then applied to Mario by dynamically adding (and removing) a class that looks like this from JavaScript:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#875D01&quot;&gt;.squishy&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;animation&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: squish &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0.5s&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178&quot;&gt;ease-in-out&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;.squishy {  animation: squish 0.5s ease-in-out;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The second contributing factor is that I am using some Astro plugins for applying some optimizations to the generated static assets. In particular, the ones that might have an effect here are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://npm.im/astro-compress&quot;&gt;&lt;code&gt;astro-compress&lt;/code&gt;&lt;/a&gt; - Compresses and minifies various assets including CSS&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://npm.im/astro-critters&quot;&gt;&lt;code&gt;astro-critters&lt;/code&gt;&lt;/a&gt; - Inlines critical CSS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I couldn’t quite pinpoint which one of these plugins (and which one of their many optimizations) was the actual culprit here, but I was able to find out that these optimizations were ultimately removing the &lt;code&gt;@keyframes&lt;/code&gt; rules from the final CSS file. This was probably happening because the &lt;code&gt;@keyframes&lt;/code&gt; rules were not being used anywhere else in the CSS and therefore they were considered &lt;em&gt;dead code&lt;/em&gt; and removed.&lt;/p&gt;
&lt;p&gt;I was able to work around the problem by defining these &lt;code&gt;@keyframes&lt;/code&gt; rules directly in my &lt;a href=&quot;https://tailwindcss.com/&quot;&gt;TailwindCSS&lt;/a&gt; configuration file. This way they are always included in the final CSS file and the animations work as expected.&lt;/p&gt;
&lt;p&gt;This one might deserve a deep dive, but for now, I am just happy the solution works.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This brings us to the end of this long and weirdly mixed blog post. I hope it gives you an idea of what it takes to migrate a static blog from Gatsby to Astro, why I ended up picking Astro (even after a first failed attempt) and some of the weird challenges and bugs that I had to face along the way.&lt;/p&gt;
&lt;p&gt;If you are really curious to deep dive into the code base, my blog is &lt;a href=&quot;https://github.com/lmammino/loige.co&quot;&gt;fully open-source&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also have &lt;a href=&quot;https://github.com/lmammino/loige.co/issues&quot;&gt;a list of issues of things that I wanted to do&lt;/a&gt;, but they were essential for the first release of the redesign, so I can do them later.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;An animation of Terminator saying &amp;quot;I&amp;amp;#x27;ll be back&amp;quot;&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;320&quot; height=&quot;320&quot; src=&quot;https://loige.co/_astro/i-ll-be-back.CvYqSjvO_Z1Wz9lA.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Let me know what you think and leave me a comment if you found this article informative or if you have any questions or suggestions!&lt;/p&gt;
&lt;p&gt;A big shout-out to all the folks who kindly provided feedback or reported bugs! Much love to you all! 😍 Special thanks to &lt;a href=&quot;https://twitter.com/paultreanordev&quot;&gt;Paul Treanor&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/willfarrell&quot;&gt;Will Farrell&lt;/a&gt; for going the extra mile with that!&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/migrating-from-gatsby-to-astro.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/migrating-from-gatsby-to-astro.png" width="1200" height="630"/></media:content><category>javascript</category><category>node-js</category><category>astro</category><author>Luciano Mammino</author><comments>https://loige.co/migrating-from-gatsby-to-astro/#comments</comments><enclosure url="https://loige.co/og/migrating-from-gatsby-to-astro.png" length="0" type="image/png"/></item><item><title>Invite-only microsites with Next.js and AirTable</title><link>https://loige.co/invite-only-microsites-with-nextjs-and-airtable/</link><guid isPermaLink="true">https://loige.co/invite-only-microsites-with-nextjs-and-airtable/</guid><description>Learn how to create a private, invite-only website using Next.js, AirTable, custom React hooks, and Vercel deploy. The post covers backend APIs in Next.js, data storage with AirTable, validating access with invite codes, collecting user input, and deploying the final app.</description><pubDate>Tue, 09 Aug 2022 07:40:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently needed to create an invite-only Next.js-powered microsite (for my wedding 🌸) and in this article I’m going to show you how I went about creating invite codes and how I implemented code validation in the app, using Next.js API endpoints and &lt;a href=&quot;https://airtable.com/invite/r/fQpMoVmw&quot;&gt;AirTable&lt;/a&gt; as a lightweight backend.&lt;/p&gt;
&lt;h2 id=&quot;the-use-case-and-the-tech-stack&quot;&gt;The use case and the tech stack&lt;/h2&gt;
&lt;p&gt;24 June 2022 was the best day of my life.&lt;/p&gt;
&lt;p&gt;Seriously, I got married with the human being I love the most and everything was just perfect.&lt;/p&gt;
&lt;p&gt;But we are not here to talk about my wedding, right?&lt;/p&gt;
&lt;p&gt;Well, we kinda are, but in a nerdy kind of way that only software engineers can (hopefully) appreciate. OK, don’t tell my wife I said that… 🤫&lt;/p&gt;
&lt;p&gt;Specifically, we will discuss how to implement an invite-only microsite to share information with all the people invited to a private event.&lt;/p&gt;
&lt;p&gt;Just to put things in context, let’s wear the PM hat for a second, and let’s discuss what kind of requirements did I impose on myself while building my wedding website:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I wanted to be able to iterate quickly, mostly focusing on content and design, not much on infrastructure.&lt;/li&gt;
&lt;li&gt;I wanted to build a simple solution that would be easy to host, maintain and update.&lt;/li&gt;
&lt;li&gt;I wanted to have a very lightweight backend, possibly something managed.&lt;/li&gt;
&lt;li&gt;Even better if I could give access to the data storage to someone else (my wife) so that we could collaborate on managing the data about the guests.&lt;/li&gt;
&lt;li&gt;If I could host everything very cheaply (if not even freely), that would be great.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For all the reasons above I settled for adopting the following pieces of tech:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Next.js&lt;/strong&gt; for building a statically rendered frontend and the backend APIs&lt;/li&gt;
&lt;li&gt;A private &lt;strong&gt;GitHub&lt;/strong&gt; repository for managing the code of the Next.js app&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vercel&lt;/strong&gt; for hosting the project&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AirTable&lt;/strong&gt; to store and manage all the data (invite codes, guests, rsvp, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Keep in mind that Next.js is free and open source, GitHub can be used for free (even if you want to keep your repo private), and Vercel and AirTable have both generous free plans that are more than enough for this kind of use case.&lt;/p&gt;
&lt;p&gt;With the stack above I ended up spending 0 money and I was able to complete the project in a couple of weekends! 🤑👌&lt;/p&gt;
&lt;h2 id=&quot;making-a-nextjs-site-private&quot;&gt;Making a Next.js site private&lt;/h2&gt;
&lt;p&gt;On top of the requirements discussed above, my wedding website had 2 additional constraints:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Every different guest should see something different (the website would look like a custom invite letter for them).&lt;/li&gt;
&lt;li&gt;People without an invite code should not be able to access any content on the website.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following illustration shows how I went about making that happen in the context of a React SPA (Single Page Application):&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Illustration showing how to make a React SPA built with Next.js invite-only using AirTable as a data storage&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;698&quot; src=&quot;https://loige.co/_astro/how-to-make-a-react-spa-invite-only.B4KnXk_6_Z1SBMv.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Please boost my ego for a second, isn’t this a beautiful illustration? 😜&lt;/p&gt;
&lt;p&gt;OK, let’s be serious:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The user loads the application by visiting the website with a personal invite code (passed as a query string parameter). When the page is loaded the React application starts on the client side. The app displays only a loading spinner at this stage.&lt;/li&gt;
&lt;li&gt;The first thing that the application does is to read the invite code from the URL. At this point, it can call the backend (a Next.js API endpoint running on Vercel) to get the invite code validated. In turn, the backend requests the data storage (an AirTable spreadsheet) to check if the code exists (in which case it’s valid). If the code exists, the backend also returns the custom information associated with that invite code. For instance, the name of the invited person.&lt;/li&gt;
&lt;li&gt;If the code is valid, the application has all the information to render the private website.&lt;/li&gt;
&lt;li&gt;If it is not valid, an error message is displayed instead.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;lets-build-an-invite-only-website&quot;&gt;Let’s build an invite-only website!&lt;/h2&gt;
&lt;p&gt;No, I am not going to show you my private wedding website (sorry, not sorry)!&lt;/p&gt;
&lt;p&gt;Instead, we are going to build a more fictional example in this article: an invite-only website for a &lt;strong&gt;secret pizza party&lt;/strong&gt;.
Here’s what different invites will look like:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Examples of different invites on our website&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2000&quot; height=&quot;718&quot; src=&quot;https://loige.co/_astro/sample-invites-pizza-party.DvzQLeS3_1IDzBQ.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;As you can see from the picture, every guest (with a valid invite code) will get a custom invite page with their name, favorite color, etc.&lt;/p&gt;
&lt;p&gt;If you want to see a preview, check out the following links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://secret-pizza-party.vercel.app/?code=14b25700-fe5b-45e8-a9be-4863b6239fcf&quot;&gt;Leonardo’s invite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://secret-pizza-party.vercel.app/?code=ce7d5886-2166-4aee-8038-548f68b9739d&quot;&gt;Michelangelo’s invite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://secret-pizza-party.vercel.app/?code=ef7ab7b7-33d5-43b9-ad73-e73bb8fd8e77&quot;&gt;Raffaello’s invite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://secret-pizza-party.vercel.app/?code=b0cbb4a4-8a31-4bc1-bee9-d6fe39c1a6b3&quot;&gt;Donatello’s invite&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, if the invite code is missing or if it’s not valid, an &lt;a href=&quot;https://secret-pizza-party.vercel.app/?invite=invalid&quot;&gt;error page&lt;/a&gt; is displayed.&lt;/p&gt;
&lt;p&gt;If you are curious to take a look at the code, it’s all &lt;a href=&quot;https://github.com/lmammino/secret-pizza-party&quot;&gt;public and hosted on GitHub&lt;/a&gt; (did you give it a star already?)…&lt;/p&gt;
&lt;h2 id=&quot;handling-sensitive-data-in-a-spa&quot;&gt;Handling sensitive data in a SPA&lt;/h2&gt;
&lt;p&gt;Sorry, I have to pause here for a second because before we get our hands dirty, we need to talk about… &lt;strong&gt;Security&lt;/strong&gt;! Security always comes first! 👷‍♀️&lt;/p&gt;
&lt;p&gt;It’s important to keep in mind that, with this particular design, all the UI logic and the content are already available in the JavaScript bundle representing the Single Page Application.&lt;/p&gt;
&lt;p&gt;On top of that, the website is hosted on Vercel, so it’s publicly available on the internet.&lt;/p&gt;
&lt;p&gt;Even if we end up displaying the “invalid invite” message to the user, a crafty user could still download all the frontend JavaScript code for our application and understand what should have been visualized with a valid invite.&lt;/p&gt;
&lt;p&gt;Let me show you what I mean with a picture:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Disclosing sensitive information in the JavaScript bundled code&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2118&quot; height=&quot;1261&quot; src=&quot;https://loige.co/_astro/disclosing-sensitive-information-in-bundled-code.CT3QgFFY_1lHRoA.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;In a dummy version of this website, I was keeping all the sensitive data (for instance here, the date and place of the event) hardcoded in my JSX code. This means that an experienced user, even if they don’t have a valid invite code, could technically have a peek at the JavaScript bundle and extrapolate a lot of sensitive information.&lt;/p&gt;
&lt;p&gt;For this reason, it’s important to keep any sensitive information outside the frontend code. In the case of a wedding website, you probably wouldn’t want to disclose to the entire world things like the event date, the location, emergency phone numbers, etc.&lt;/p&gt;
&lt;p&gt;All the data that we need to keep private (only available to someone with a valid invite code) must be fetched doing an API call to the backend.&lt;/p&gt;
&lt;p&gt;In a way, we can imagine the invite code as an API key that gives people access not just to the website, but also to all the sensitive data that the website will display.&lt;/p&gt;
&lt;p&gt;Of course, make sure to keep your repository private, otherwise, that might become another way to access sensitive information embedded in your API code…&lt;/p&gt;
&lt;p&gt;Finally, it’s also important that your user understand that they shouldn’t be sharing their unique URL with other people. So make sure to warn them when you send them the invite URL.&lt;/p&gt;
&lt;p&gt;In summary, here are some good security rules we will abide by:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The website is public&lt;/li&gt;
&lt;li&gt;We are enforcing access control from the client side&lt;/li&gt;
&lt;li&gt;The client-side cannot be trusted (all its code is publicly accessible)&lt;/li&gt;
&lt;li&gt;A backend needs to be used to validate the code and return any sensitive information that needs to be accessible only with a valid invite code.&lt;/li&gt;
&lt;li&gt;For extra security, keep your repo private and make sure your user won’t share their invite URL with other people!&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;generating-and-storing-invite-codes&quot;&gt;Generating and storing invite codes&lt;/h2&gt;
&lt;p&gt;We said we are going to be using &lt;a href=&quot;https://airtable.com/invite/r/fQpMoVmw&quot;&gt;AirTable&lt;/a&gt; as storage for invite code and related information.&lt;/p&gt;
&lt;p&gt;AirTable is a SaaS that allows you to easily manage different kinds of datasets. You can do a lot through its web interface, but you can also use the data programmatically, turning it into a convenience database for simple types of applications.&lt;/p&gt;
&lt;p&gt;For this particular use case, Airtable offers a &lt;a href=&quot;https://support.airtable.com/hc/en-us/articles/203313985-Public-REST-API&quot;&gt;public REST API&lt;/a&gt; and SDKs in various programming languages, including &lt;a href=&quot;https://github.com/airtable/airtable.js&quot;&gt;JavaScript&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We can start by creating a new &lt;em&gt;base&lt;/em&gt; (which is kinda a workspace in AirTable lingo) and create a grid data view into it.&lt;/p&gt;
&lt;p&gt;This first data table will contain all our invite codes, so let’s call it &lt;strong&gt;invites&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;An example of how we could structure the AirTable table&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1270&quot; height=&quot;334&quot; src=&quot;https://loige.co/_astro/airtable-sample-table.FUMT4J2T_AF3bu.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;As displayed in the picture above we are adding a few fields there:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;invite&lt;/code&gt;: a UUID that represents the invite code&lt;/li&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt;: the name of the invited guest&lt;/li&gt;
&lt;li&gt;&lt;code&gt;favouriteColor&lt;/code&gt;the favorite color of the guest&lt;/li&gt;
&lt;li&gt;&lt;code&gt;weapon&lt;/code&gt;the weapons of the guest (small note: in real life I am not pro weapons, but if you haven’t got it yet, we are talking about Mutant Ninja Turtles™️ here… 😝)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This makes sense for our fictional example. In a more generic use case, you’ll be adding here all the pieces of information that are unique for every single guest.
Note that on this website we also have a mini RSVP form. This means that we will be able to collect some data from the users. This is also something that we will be storing in AirTable.&lt;/p&gt;
&lt;details style=&quot;margin-top: 1em&quot;&gt;
  &lt;summary&gt;Are you following along and want an easy way to import this table into your Airtable base? (expand here)&lt;/summary&gt;
  &lt;div style=&quot;background: #eee; margin-top: 1em; padding: 1em; border: 2px dotted #ccc; border-radius: 10px;&quot;&gt;
&lt;p&gt;Airtable allows to import data into a base from a CSV, so here’s my example data in CSV format:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;invite,name,favouriteColor,weapon&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;14b25700-fe5b-45e8-a9be-4863b6239fcf,Leonardo,blue,Twin Katana&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;ce7d5886-2166-4aee-8038-548f68b9739d,Michelangelo,orange,Nunchaku&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;ef7ab7b7-33d5-43b9-ad73-e73bb8fd8e77,Raffaello,red,Twin Sai&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;b0cbb4a4-8a31-4bc1-bee9-d6fe39c1a6b3,Donatello,purple,Bo&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;invite,name,favouriteColor,weapon14b25700-fe5b-45e8-a9be-4863b6239fcf,Leonardo,blue,Twin Katanace7d5886-2166-4aee-8038-548f68b9739d,Michelangelo,orange,Nunchakuef7ab7b7-33d5-43b9-ad73-e73bb8fd8e77,Raffaello,red,Twin Saib0cbb4a4-8a31-4bc1-bee9-d6fe39c1a6b3,Donatello,purple,Bo&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/details&gt;
&lt;h2 id=&quot;reading-invite-codes-using-the-airtable-sdk&quot;&gt;Reading invite codes using the AirTable SDK&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: from this point I will assume that you have already scaffolded your Next.js application. If you need help doing that you can check out &lt;a href=&quot;https://nextjs.org/learn/basics/create-nextjs-app&quot;&gt;The official Next.js docs&lt;/a&gt; or just run the following command:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;create-next-app@latest&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--typescript&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--use-npm&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npx create-next-app@latest --typescript --use-npm&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Also note that, at the time of writing, I am using &lt;strong&gt;Next.js version 12.2&lt;/strong&gt;. If you are reading this in a distant future, you might have to change something in the following code examples!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Because we are using TypeScript, the first thing that we want to do is spend a few minutes to think how to represent our invites.&lt;/p&gt;
&lt;p&gt;The easiest thing I could come up with was to create a file called &lt;code&gt;types/invite.ts&lt;/code&gt; with the following definition:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Invite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;favouriteColor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;weapon&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;coming&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;boolean&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;export interface Invite {  code: string  name: string  favouriteColor: string  weapon: string  coming?: boolean}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This should probably be enough for our use case.&lt;/p&gt;
&lt;p&gt;Now is the time to start writing some code to interact with the data on our AirTable &lt;em&gt;base&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;To do that, the first thing we need to install the &lt;code&gt;airtable&lt;/code&gt; package:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--save&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;airtable&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;npm i --save airtable&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We will also need to grab our Airtable API KEY from the &lt;a href=&quot;https://airtable.com/account&quot;&gt;AirTable account page&lt;/a&gt; and the &lt;em&gt;base ID&lt;/em&gt; from the &lt;a href=&quot;https://airtable.com/api&quot;&gt;API page&lt;/a&gt; (select your workspace and the API docs should show you the &lt;em&gt;base ID&lt;/em&gt; in the introduction section).&lt;/p&gt;
&lt;p&gt;For development convenience we are going to store these two variables as environment variables:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;AIRTABLE_API_KEY&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;put your api key here&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;AIRTABLE_BASE_ID&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;put your base id here&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;export AIRTABLE_API_KEY=&amp;#x22;put your api key here&amp;#x22;export AIRTABLE_BASE_ID=&amp;#x22;put your base id here&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If you go back to the API docs, you might appreciate that the docs are automatically generated for your workspace. You should see a section called “invites table” describing all the fields available in our grid!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Example of documentation page for AirTable&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2552&quot; height=&quot;1333&quot; src=&quot;https://loige.co/_astro/airtable-api-documentation-page.DBNpvl8F_ReiES.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Isn’t this an awesome way to provide documentation?! And you can even get a bunch of &lt;code&gt;curl&lt;/code&gt; and JavaScript code examples.&lt;/p&gt;
&lt;p&gt;What we want to do right now is to be able to retrieve a record by invite code. One way to do that is to list all the records and use a filter to try to match based on our invite code field. We can visit the section &lt;em&gt;List records&lt;/em&gt; to have a feeling for how we could do that. If we switch to the JavaScript code example we will see something like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Airtable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;airtable&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;base&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Airtable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;apiKey&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;YOUR_API_KEY&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; }).&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;base&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;YOUR_BASE_ID&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;base&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;invites&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;select&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Selecting the first 3 records in Grid view:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;maxRecords&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;view&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Grid view&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;eachPage&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;page&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;records&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;fetchNextPage&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// This function (`page`) will get called for each page of records.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;records&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Retrieved&apos;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;invite&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// To fetch the next page of records, call `fetchNextPage`.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// If there are more records, `page` will get called again.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// If there are no more records, `done` will get called.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fetchNextPage&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;done&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;var Airtable = require(&amp;#x27;airtable&amp;#x27;)var base = new Airtable({ apiKey: &amp;#x27;YOUR_API_KEY&amp;#x27; }).base(&amp;#x27;YOUR_BASE_ID&amp;#x27;)base(&amp;#x27;invites&amp;#x27;)  .select({    // Selecting the first 3 records in Grid view:    maxRecords: 3,    view: &amp;#x27;Grid view&amp;#x27;,  })  .eachPage(    function page(records, fetchNextPage) {      // This function (&amp;#x60;page&amp;#x60;) will get called for each page of records.      records.forEach(function (record) {        console.log(&amp;#x27;Retrieved&amp;#x27;, record.get(&amp;#x27;invite&amp;#x27;))      })      // To fetch the next page of records, call &amp;#x60;fetchNextPage&amp;#x60;.      // If there are more records, &amp;#x60;page&amp;#x60; will get called again.      // If there are no more records, &amp;#x60;done&amp;#x60; will get called.      fetchNextPage()    },    function done(err) {      if (err) {        console.error(err)        return      }    },  )&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;OK Airtable, you did such a great job with the auto-generated docs, but come on! What kind of JavaScript is this?! Still using &lt;code&gt;var&lt;/code&gt;, &lt;em&gt;CommonJS&lt;/em&gt;, and &lt;em&gt;callbacks&lt;/em&gt;? 😢&lt;/p&gt;
&lt;p&gt;Well, I guess we will need to roll up our sleeves and do a bit of extra work to make this nice and modern…&lt;/p&gt;
&lt;p&gt;Let’s start by creating a new file called &lt;code&gt;utils/airtable.ts&lt;/code&gt; and let’s create a helper function there to get an invite by id:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;typescript&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Airtable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;airtable&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Invite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;../types/invite&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// make sure all the necessary env vars are set&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;AIRTABLE_API_KEY&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;AIRTABLE_API_KEY is not set&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;AIRTABLE_BASE_ID&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;AIRTABLE_BASE_ID is not set&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// create a new Airtable client and gets a reference to the&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// airtable base containing our invites&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;airtable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Airtable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;apiKey&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;AIRTABLE_API_KEY&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;base&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;airtable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;base&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;AIRTABLE_BASE_ID&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// get an invite by invite code (promisified)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getInvite&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteCode&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Invite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;reject&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;base&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;invites&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// runs a query on the `invites` table&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;select&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;filterByFormula&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`{invite} = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;escape&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteCode&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;maxRecords&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// reads the first page of results&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;firstPage&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;records&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// propagate errors&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;reject&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// if the record could not be found&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// we consider it an error&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;records&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;records&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;reject&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Invite not found&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// otherwise we create an invite object from the first record&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// (there should be only one with the give code) and return it&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;records&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;fields&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;invite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;records&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;fields&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;favouriteColor&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;records&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;fields&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;favouriteColor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;weapon&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;records&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;fields&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;weapon&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;coming&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#016C9A&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;records&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;fields&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;coming&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;undefined&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;undefined&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;              &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;records&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;fields&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;coming&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;yes&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import Airtable from &amp;#x27;airtable&amp;#x27;import { Invite } from &amp;#x27;../types/invite&amp;#x27;// make sure all the necessary env vars are setif (!process.env.AIRTABLE_API_KEY) {  throw new Error(&amp;#x27;AIRTABLE_API_KEY is not set&amp;#x27;)}if (!process.env.AIRTABLE_BASE_ID) {  throw new Error(&amp;#x27;AIRTABLE_BASE_ID is not set&amp;#x27;)}// create a new Airtable client and gets a reference to the// airtable base containing our invitesconst airtable = new Airtable({ apiKey: process.env.AIRTABLE_API_KEY })const base = airtable.base(process.env.AIRTABLE_BASE_ID)// get an invite by invite code (promisified)export function getInvite(inviteCode: string): Promise&lt;Invite&gt; {  return new Promise((resolve, reject) =&gt; {    base(&amp;#x27;invites&amp;#x27;)      // runs a query on the &amp;#x60;invites&amp;#x60; table      .select({        filterByFormula: &amp;#x60;{invite} = ${escape(inviteCode)}&amp;#x60;,        maxRecords: 1,      })      // reads the first page of results      .firstPage((err, records) =&gt; {        if (err) {          // propagate errors          console.error(err)          return reject(err)        }        // if the record could not be found        // we consider it an error        if (!records || records.length === 0) {          return reject(new Error(&amp;#x27;Invite not found&amp;#x27;))        }        // otherwise we create an invite object from the first record        // (there should be only one with the give code) and return it        const result = {          code: String(records[0].fields.invite),          name: String(records[0].fields.name),          favouriteColor: String(records[0].fields.favouriteColor),          weapon: String(records[0].fields.weapon),          coming:            typeof records[0].fields.coming === &amp;#x27;undefined&amp;#x27;              ? undefined              : records[0].fields.coming === &amp;#x27;yes&amp;#x27;,        }        resolve(result)      })  })}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;I left enough comments in the code, that an additional explanation should not be necessary!
We are essentially using the &lt;code&gt;airtable&lt;/code&gt; SDK and building a nicer promise-based interface to get an invite by invite code.&lt;/p&gt;
&lt;p&gt;Ok, for the eagle-eyed ones, you are probably wondering where the heck is that &lt;code&gt;escape&lt;/code&gt; function coming from?! I elided it from the code to keep things simple. The TLDR; is that &lt;strong&gt;it makes things more secure&lt;/strong&gt; by reducing the risk of &lt;em&gt;injections&lt;/em&gt;.&lt;/p&gt;
&lt;details style=&quot;margin-top: 1em&quot;&gt;
  &lt;summary&gt;But &quot;the how&quot; needs a bit of a long-ish explanation (expand here if you are curious. Yes, you should be!).&lt;/summary&gt;
  &lt;div style=&quot;background: #eee; margin-top: 1em; padding: 1em; border: 2px dotted #ccc; border-radius: 10px;&quot;&gt;
&lt;p&gt;Every time you use user input to construct some kind of query, your spider senses should be immediately triggered! 🕷&lt;/p&gt;
&lt;p&gt;The invite code is, in fact, user-controlled. It’s part of the query string in the URL. A user can decide to change that and try to see what happens with different values.&lt;/p&gt;
&lt;p&gt;If the user inputs &lt;code&gt;?code=14b25700-fe5b-45e8-a9be-4863b6239fcf&lt;/code&gt; as invite code, with a naïve string interpolation, we would be producing the following Airtable formula:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;{invite} = &apos;14b25700-fe5b-45e8-a9be-4863b6239fcf&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{invite} = &amp;#x27;14b25700-fe5b-45e8-a9be-4863b6239fcf&amp;#x27;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;But what if a very evil user tries something like &lt;code&gt;?code=%27%20&gt;%3D%200%20%26%20%27&lt;/code&gt; (&lt;code&gt;?code=&apos; &gt;= 0 &amp;#x26; &apos;&lt;/code&gt; unencoded)?!&lt;/p&gt;
&lt;p&gt;In this case, we end up constructing the following Airtable formula:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;{invite} = &apos;&apos; &gt;= 0 &amp;#x26; &apos;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;{invite} = &amp;#x27;&amp;#x27; &gt;= 0 &amp;#x26; &amp;#x27;&amp;#x27;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Which always evaluates to &lt;code&gt;1&lt;/code&gt; (&lt;code&gt;true&lt;/code&gt;) for every record in the table! So this very evil user is now accessing your private website without having to know a valid code. They will just get the code of the first record that Airtable matches in the table! If you don’t believe me you can try this attack by yourself &lt;a href=&quot;https://secret-pizza-party-fgpypfb66-lmammino.vercel.app/?code=%27%20%3E%3D%200%20%26%20%27&quot;&gt;with this link&lt;/a&gt; (running on a &lt;a href=&quot;https://github.com/lmammino/secret-pizza-party/tree/vulnerable&quot;&gt;vulnerable branch&lt;/a&gt; of the app where we don’t perform the escape).&lt;/p&gt;
&lt;p&gt;This is like &lt;a href=&quot;https://owasp.org/www-community/attacks/SQL_Injection&quot;&gt;SQL injections&lt;/a&gt; but for Airtable filter formulas! 😱&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;escape&lt;/code&gt; function, allows us to try to sanitize user input and escape dangerous characters like &lt;code&gt;&apos;&lt;/code&gt; and &lt;code&gt;&quot;&lt;/code&gt; which might allow a malicious actor to alter the structure of our filter formula.&lt;/p&gt;
&lt;p&gt;If you are curious this is my basic implementation of the &lt;code&gt;escape&lt;/code&gt; function (the one I used in this project), but I have to say I am quite disappointed that Airtable does not provide a built-in utility for this in their SDK and that they don’t warn their users about this threat in their docs… 🙁&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;escape&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;value&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#016C9A&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;undefined&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;BLANK()&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#016C9A&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;string&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;escapedString&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;value&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;replace&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#D67B7B;--1:#016C9A&quot;&gt;/&apos;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;replace&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#D67B7B;--1:#016C9A&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--0:#D67B7B;--1:#875D01&quot;&gt;\r&lt;/span&gt;&lt;span style=&quot;--0:#D67B7B;--1:#016C9A&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;replace&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--1:#016C9A&quot;&gt;&lt;span style=&quot;--0:#D67B7B&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;--0:#D67B7B&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\\\\&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;replace&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#D67B7B;--1:#016C9A&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--0:#D67B7B;--1:#875D01&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;--0:#D67B7B;--1:#016C9A&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;n&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;replace&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#D67B7B;--1:#016C9A&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--0:#D67B7B;--1:#875D01&quot;&gt;\t&lt;/span&gt;&lt;span style=&quot;--0:#D67B7B;--1:#016C9A&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;g&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;t&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`&apos;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;escapedString&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;`&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#016C9A&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#016C9A&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;boolean&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;1&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;0&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Invalid value received&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;function escape(value: string): string {  if (value === null || typeof value === &amp;#x27;undefined&amp;#x27;) {    return &amp;#x27;BLANK()&amp;#x27;  }  if (typeof value === &amp;#x27;string&amp;#x27;) {    const escapedString = value      .replace(/&amp;#x27;/g, &amp;#x22;\\&amp;#x27;&amp;#x22;)      .replace(/\r/g, &amp;#x27;&amp;#x27;)      .replace(/\\/g, &amp;#x27;\\\\&amp;#x27;)      .replace(/\n/g, &amp;#x27;\\n&amp;#x27;)      .replace(/\t/g, &amp;#x27;\\t&amp;#x27;)    return &amp;#x60;&amp;#x27;${escapedString}&amp;#x27;&amp;#x60;  }  if (typeof value === &amp;#x27;number&amp;#x27;) {    return String(value)  }  if (typeof value === &amp;#x27;boolean&amp;#x27;) {    return value ? &amp;#x27;1&amp;#x27; : &amp;#x27;0&amp;#x27;  }  throw Error(&amp;#x27;Invalid value received&amp;#x27;)}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note that &lt;strong&gt;this function does not claim to be perfect or comprehensive&lt;/strong&gt;. I haven’t extensively tested it, nor do I know all the bells and whistles of the formula syntax to be able to do that. If you are doing something like this in your code, make sure to test this extensively.&lt;/p&gt;
&lt;p&gt;PS: I nudged Airtable &lt;a href=&quot;https://twitter.com/loige/status/1555622372085997569&quot;&gt;on Twitter&lt;/a&gt; (with no response) and &lt;a href=&quot;https://community.airtable.com/t/standard-way-to-prevent-formula-injections-when-using-airtable-as-a-backend-through-sdk/50283&quot;&gt;their community forum&lt;/a&gt; (well, let’s just say that the thread wasn’t received particularly well by some members of the community and that the conversation derailed a little…). I also reached out to their support channels and, hopefully, this will get somewhere…&lt;/p&gt;
  &lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;Now that we have created this utility function, we can use it in an API to be able to provide code validation and invite data to the frontend.&lt;/p&gt;
&lt;h2 id=&quot;nextjs-invite-endpoint&quot;&gt;Next.js invite endpoint&lt;/h2&gt;
&lt;p&gt;I am generally not a big fan of convention-based frameworks like Next.js. Conventions cannot be comprehensive and sometimes you find yourself trying to adapt your problem to whatever convention the framework is forcing you to use, rather than adopting the optimal approach for the problem at hand.&lt;/p&gt;
&lt;p&gt;In any case, I find that I enjoy using Next.js for small personal projects. The level of productivity is generally quite high and Next.js can make your life easy in many different ways.&lt;/p&gt;
&lt;p&gt;One of the features that I love the most is how easy it is to build APIs for the frontend application.&lt;/p&gt;
&lt;p&gt;To create an API endpoint you just need to create a file under &lt;code&gt;pages/api&lt;/code&gt;. For instance, if you want to create a hello world API, you could simply create the following file in &lt;code&gt;pages/api/hello.ts&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;NextApiRequest&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;NextApiResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;next&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#AF4238&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;handler&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;NextApiRequest&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;res&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;NextApiResponse&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;&amp;#x3C;{ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;message&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; }&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;res&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Hello World&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import type { NextApiRequest, NextApiResponse } from &amp;#x27;next&amp;#x27;export default async function handler(  req: NextApiRequest,  res: NextApiResponse&lt;{ message: string }&gt;,) {  return res.status(200).json({ message: &amp;#x27;Hello World&amp;#x27; })}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now you can simply call this API by sending a request to &lt;code&gt;http://localhost:3000/api/hello&lt;/code&gt;. The convention says that the API path follows the file name (&lt;code&gt;hello.ts&lt;/code&gt; -&gt; &lt;code&gt;/api/hello&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;❯ curl -i http://localhost:3000/api/hello&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;HTTP/1.1 200 OK&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Content-Type: application/json; charset=utf-8&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;ETag: &quot;19-c6Hfa5VVP+Ghysj+6y9cPi5QQbk&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Content-Length: 25&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Vary: Accept-Encoding&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Date: Sun, 07 Aug 2022 16:25:20 GMT&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Connection: keep-alive&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Keep-Alive: timeout=5&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;{&quot;message&quot;:&quot;Hello World&quot;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;❯ curl -i http://localhost:3000/api/helloHTTP/1.1 200 OKContent-Type: application/json; charset=utf-8ETag: &amp;#x22;19-c6Hfa5VVP+Ghysj+6y9cPi5QQbk&amp;#x22;Content-Length: 25Vary: Accept-EncodingDate: Sun, 07 Aug 2022 16:25:20 GMTConnection: keep-aliveKeep-Alive: timeout=5{&amp;#x22;message&amp;#x22;:&amp;#x22;Hello World&amp;#x22;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If you want to learn more about how to create API endpoints with Next.js check out the &lt;a href=&quot;https://nextjs.org/docs/api-routes/introduction&quot;&gt;official documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ok, so let’s use what we just learned to create an API endpoint that allows the frontend to validate the user invite code and retrieve the related invite data. Let’s create write our code in &lt;code&gt;pages/api/invite.ts&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;NextApiRequest&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;NextApiResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;next&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;InviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;../../types/invite&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;getInvite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;../../utils/airtable&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;messages&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;../../data/messages&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#AF4238&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;handler&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;NextApiRequest&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;res&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;NextApiResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;InviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; }&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// if the request is not a GET, return an error&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;method&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!==&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;GET&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;res&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;405&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Method Not Allowed&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// if the code is missing we return a 400 error&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;res&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;400&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Missing invite code&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// If there are multiple invite codes (?code=x&amp;#x26;code=y)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// we pick the first one and ignore the rest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;isArray&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;code&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// we use our Airtable utility to get the invite data for a given code&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// and return the result to the user&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;invite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getInvite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;res&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;invite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;messages&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// In case of error we return either a 401 or a 500 error:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// - if the code was not found we return 401&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// - otherwise we return a generic 500 server error&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Error&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;res&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Invite not found&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;401&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;500&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import type { NextApiRequest, NextApiResponse } from &amp;#x27;next&amp;#x27;import { InviteResponse } from &amp;#x27;../../types/invite&amp;#x27;import { getInvite } from &amp;#x27;../../utils/airtable&amp;#x27;import messages from &amp;#x27;../../data/messages&amp;#x27;export default async function handler(  req: NextApiRequest,  res: NextApiResponse&lt;InviteResponse | { error: string }&gt;,) {  // if the request is not a GET, return an error  if (req.method !== &amp;#x27;GET&amp;#x27;) {    return res.status(405).json({ error: &amp;#x27;Method Not Allowed&amp;#x27; })  }  // if the code is missing we return a 400 error  if (!req.query.code) {    return res.status(400).json({ error: &amp;#x27;Missing invite code&amp;#x27; })  }  // If there are multiple invite codes (?code=x&amp;#x26;code=y)  // we pick the first one and ignore the rest  const code = Array.isArray(req.query.code)    ? req.query.code[0]    : req.query.code  try {    // we use our Airtable utility to get the invite data for a given code    // and return the result to the user    const invite = await getInvite(code)    res.status(200).json({ invite, messages })  } catch (err) {    // In case of error we return either a 401 or a 500 error:    // - if the code was not found we return 401    // - otherwise we return a generic 500 server error    const e = err as Error    res      .status(e.message === &amp;#x27;Invite not found&amp;#x27; ? 401 : 500)      .json({ error: e.message })  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Once again the code is sufficiently commented out, so, hopefully, it’s easy enough to follow.&lt;/p&gt;
&lt;p&gt;But there are a few details that we need to discuss: what the &lt;code&gt;InviteResponse&lt;/code&gt; type is and what the &lt;code&gt;messages&lt;/code&gt; variable is.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;InviteResponse&lt;/code&gt; is a type that I have sneakily added to &lt;code&gt;types/invite.ts&lt;/code&gt;, which now looks like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Messages&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;../data/messages&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Invite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ... (unchanged, elided for brevity)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;InviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;invite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Invite&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;messages&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Messages&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { Messages } from &amp;#x27;../data/messages&amp;#x27;export interface Invite {  // ... (unchanged, elided for brevity)}export interface InviteResponse {  invite: Invite  messages: Messages}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The idea is that when a user has a valid code we want this API to return 2 different pieces of information:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;All the data associated with the invite (inside &lt;code&gt;invite&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;All the sensitive messages that the UI will need to display to &lt;em&gt;authenticated&lt;/em&gt; users.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All the messages are stored in &lt;code&gt;data/messages.ts&lt;/code&gt;, which currently looks like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;messages&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Secret Pizza Party!&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;date_and_place&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Dec 31st 2022 - 122 and 1/8th, New York City&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;invitation&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;You have been invited to the most awesome secret pizza party of the year!&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;question&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Are you coming?&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;answer1&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Cowabunga! (yes)&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;answer2&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Nitwits! (no)&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;secret_person&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Shredder&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Messages&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#016C9A&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;messages&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#AF4238&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;messages&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;const messages = {  title: &amp;#x27;Secret Pizza Party!&amp;#x27;,  date_and_place: &amp;#x27;Dec 31st 2022 - 122 and 1/8th, New York City&amp;#x27;,  invitation:    &amp;#x27;You have been invited to the most awesome secret pizza party of the year!&amp;#x27;,  question: &amp;#x27;Are you coming?&amp;#x27;,  answer1: &amp;#x27;Cowabunga! (yes)&amp;#x27;,  answer2: &amp;#x27;Nitwits! (no)&amp;#x27;,  secret_person: &amp;#x27;Shredder&amp;#x27;,}export type Messages = typeof messagesexport default messages&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The reason why we return these messages from the API (rather than embedding them in the frontend application code) is that this way these messages won’t be included in the JavaScript bundle. So, a user without an invite code won’t be able to extract potentially sensitive information from the JavaScript bundle of the frontend application.&lt;/p&gt;
&lt;h2 id=&quot;invite-validation-in-react&quot;&gt;Invite validation in React&lt;/h2&gt;
&lt;p&gt;Great!&lt;/p&gt;
&lt;p&gt;At this point, we have a &lt;em&gt;mini-database&lt;/em&gt; (if we want to call our AirTable table like that) and an API to get invite data.&lt;/p&gt;
&lt;p&gt;We can finally start to work on the frontend!&lt;/p&gt;
&lt;p&gt;The first thing that we can do is to build a &lt;strong&gt;custom React hook&lt;/strong&gt; that can do the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Grab the invite code from the current URL&lt;/li&gt;
&lt;li&gt;Call the invite API using the invite code&lt;/li&gt;
&lt;li&gt;Expose the returned invite data and the messages&lt;/li&gt;
&lt;li&gt;Also, expose possible errors throughout the process&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I am going to go ahead and show you the code (&lt;code&gt;components/hooks/useInvite.tsx&lt;/code&gt;), but if you want to review React docs on how to build custom hooks &lt;a href=&quot;https://reactjs.org/docs/hooks-custom.html&quot;&gt;here’s the page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Our custom hook will be using React’s built-in &lt;a href=&quot;https://reactjs.org/docs/hooks-state.html&quot;&gt;&lt;code&gt;useState&lt;/code&gt;&lt;/a&gt; hook to handle state and &lt;a href=&quot;https://reactjs.org/docs/hooks-effect.html&quot;&gt;&lt;code&gt;useEffect&lt;/code&gt;&lt;/a&gt; to run code on component mount.&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;tsx&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;useState&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;useEffect&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;react&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;InviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;../../types/invite&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Defines the endpoint based on the current window location&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;API_BASE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#016C9A&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;window&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!==&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;undefined&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;window&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;location&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;origin&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/api&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;INVITE_ENDPOINT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;API_BASE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/invite&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Helper function that uses fetch to invoke the invite API endpoint&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fetchInvite&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;code&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;InviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;requestUrl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;URL&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;INVITE_ENDPOINT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;requestUrl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;searchParams&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;code&apos;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fetch&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;requestUrl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Invalid code&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;invite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;invite&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// The custom hook&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#AF4238&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;useInvite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;InviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// This hook has the inviteResponse and a possilbe error as state.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;inviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;setInviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;useState&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;InviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;setError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;useState&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// We want to make the API call when the component using the hook&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// is mounted so we use the useEffect hook.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;useEffect&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// We read the code from the current window URL.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;URL&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;window&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;location&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;toString&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;searchParams&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;code&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// If there is no code, we set an error message.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;setError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;No code provided&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// If we have a code, we get the associated data.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// In case of success or failure we update the state accordingly.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fetchInvite&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;setInviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;setError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}, [])&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// We return the state variables.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import { useState, useEffect } from &amp;#x27;react&amp;#x27;import { InviteResponse } from &amp;#x27;../../types/invite&amp;#x27;// Defines the endpoint based on the current window locationconst API_BASE =  typeof window !== &amp;#x27;undefined&amp;#x27; &amp;#x26;&amp;#x26; window.location.origin + &amp;#x27;/api&amp;#x27;const INVITE_ENDPOINT = API_BASE + &amp;#x27;/invite&amp;#x27;// Helper function that uses fetch to invoke the invite API endpointasync function fetchInvite(code: string): Promise&lt;InviteResponse&gt; {  const requestUrl = new URL(INVITE_ENDPOINT)  requestUrl.searchParams.append(&amp;#x27;code&amp;#x27;, code)  const response = await fetch(requestUrl)  if (!response.ok) {    throw new Error(&amp;#x27;Invalid code&amp;#x27;)  }  const invite = await response.json()  return invite}// The custom hookexport default function useInvite(): [InviteResponse | null, string | null] {  // This hook has the inviteResponse and a possilbe error as state.  const [inviteResponse, setInviteResponse] = useState&lt;InviteResponse | null&gt;(    null,  )  const [error, setError] = useState&lt;string | null&gt;(null)  // We want to make the API call when the component using the hook  // is mounted so we use the useEffect hook.  useEffect(() =&gt; {    // We read the code from the current window URL.    const url = new URL(window.location.toString())    const code = url.searchParams.get(&amp;#x27;code&amp;#x27;)    if (!code) {      // If there is no code, we set an error message.      setError(&amp;#x27;No code provided&amp;#x27;)    } else {      // If we have a code, we get the associated data.      // In case of success or failure we update the state accordingly.      fetchInvite(code)        .then(setInviteResponse)        .catch((err) =&gt; {          setError(err.message)        })    }  }, [])  // We return the state variables.  return [inviteResponse, error]}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We can now import this hook into any component and use it like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;tsx&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;React&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;react&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;useInvite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;./hooks/useInvite&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#AF4238&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;SomeExampleComponent&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;inviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;useInvite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// there was an error&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;... some error happened&lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// still loading the data from the backend&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;Loading ...&lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// has the data!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;actual component markup when inviteResponse is available&lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import React from &amp;#x27;react&amp;#x27;import useInvite from &amp;#x27;./hooks/useInvite&amp;#x27;export default function SomeExampleComponent() {  const [inviteResponse, error] = useInvite()  // there was an error  if (error) {    return &lt;div&gt;... some error happened&lt;/div&gt;  }  // still loading the data from the backend  if (!inviteResponse) {    return &lt;div&gt;Loading ...&lt;/div&gt;  }  // has the data!  return &lt;div&gt;actual component markup when inviteResponse is available&lt;/div&gt;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note how the hook nicely abstracts the data fetching operation, but we still need to keep into account that this operation will be asynchronous and we need to handle the 3 possible states: &lt;em&gt;loading&lt;/em&gt;, success, and error.&lt;/p&gt;
&lt;p&gt;The code above is very similar to the actual &lt;code&gt;Home&lt;/code&gt; component in our application. There isn’t much value in showing the entire source code here once you understand the idea, but if you are curious you can find the full source in &lt;a href=&quot;https://github.com/lmammino/secret-pizza-party/blob/main/components/Home.tsx&quot;&gt;&lt;code&gt;components/Home.tsx&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At this point, the only thing that is missing is to use the &lt;code&gt;Home&lt;/code&gt; component in the single page that we are going to have in our Next.js application (it’s a Single Page Application after all).&lt;/p&gt;
&lt;p&gt;In Next.js, page components are components inside the &lt;code&gt;page&lt;/code&gt; directory. In our case we will only have the index page, so the component is &lt;a href=&quot;https://github.com/lmammino/secret-pizza-party/blob/main/pages/index.tsx&quot;&gt;&lt;code&gt;pages/index.tsx&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, if you run the application locally, you should have a loading screen and then a success error (with a valid invite code) or an error (if you didn’t provide a code or if you have an invalid one). 🎉&lt;/p&gt;
&lt;h2 id=&quot;collecting-user-data&quot;&gt;Collecting user data&lt;/h2&gt;
&lt;p&gt;So far we have only been reading data from our Airtable table, but nothing is stopping us from also writing data into it!&lt;/p&gt;
&lt;p&gt;For example, once a user reaches their invite page, they have an option to RSVP to the event. How are we going to store their answer?&lt;/p&gt;
&lt;p&gt;The simplest idea that comes to mind is to add a new column to our table for the field “coming”:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Airtable option field to track whether guests are coming or not&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;2188&quot; height=&quot;672&quot; src=&quot;https://loige.co/_astro/airtable-option-field-coming.C5dlEepG_28M81A.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;The field we added is a &lt;strong&gt;single select&lt;/strong&gt; type of field. We added two possible values: &lt;strong&gt;yes&lt;/strong&gt; and &lt;strong&gt;no&lt;/strong&gt;. In alternative we could have used a boolean field, but with this approach it we actually can manage 3 possible states for user RSVP:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;unknown&lt;/em&gt; (the gues hasn’t submitted their RSVP yet)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;coming&lt;/em&gt; (“yes”)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;not coming&lt;/em&gt; (“no”)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now you know why we have originally defined a &lt;code&gt;coming&lt;/code&gt; field (optional boolean) in our &lt;code&gt;Invite&lt;/code&gt; interface and why we were popoluating it in our &lt;code&gt;utils/airtable.ts&lt;/code&gt; helper file! 🙃&lt;/p&gt;
&lt;p&gt;In order to be allow our guests to submit their RSVP we need to do 4 main changes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Update the Airtable utility file with a function to update the &lt;code&gt;coming&lt;/code&gt; field for a recod&lt;/li&gt;
&lt;li&gt;Create a new API endpoint to collects RSVP (using the new utility function from point 1.)&lt;/li&gt;
&lt;li&gt;Update our &lt;code&gt;useInvite&lt;/code&gt; hook to provide functionality to submit the RSVP (and handle progress)&lt;/li&gt;
&lt;li&gt;Update the frontend to use the new functionality provided by the &lt;code&gt;useInvite&lt;/code&gt; hook&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We’ll be doing some good amount of refactoring to introduce these changes, so let’s roll up our sleeves and warm up our keyboards!&lt;/p&gt;
&lt;h3 id=&quot;the-rsvp-airtable-utility&quot;&gt;The RSVP Airtable utility&lt;/h3&gt;
&lt;p&gt;In Airtable, every record in a table has a unique ID. If we know the ID we can use it to update one or more fields in that record.&lt;/p&gt;
&lt;p&gt;In our application we have been using the invite code as unique ID and we already have some code written to be able to fetch a record by invite code.&lt;/p&gt;
&lt;p&gt;It would be a good idea to refactor that code and extract the part that fetches a raw Airtable record. This way we can use this functionality in both our &lt;em&gt;retrieval&lt;/em&gt; and &lt;em&gt;update&lt;/em&gt; function (the latter which we still have to write).&lt;/p&gt;
&lt;p&gt;So let’s open our file &lt;code&gt;utils/airtable.ts&lt;/code&gt; again and add the following changes:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Airtable&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;FieldSet&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;Record&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;airtable&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getInviteRecord&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteCode&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Record&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;FieldSet&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;reject&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;base&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;invites&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// runs a query on the `invites` table&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;select&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;filterByFormula&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`{invite} = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;escape&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteCode&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;maxRecords&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// reads the first page of results&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;firstPage&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;records&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// propagate errors&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;reject&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// if the record could not be found&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// we consider it an error&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;records&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;records&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;reject&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Invite not found&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// returns the first record&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;records&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;])&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import Airtable, { FieldSet, Record } from &amp;#x27;airtable&amp;#x27;// ...export function getInviteRecord(inviteCode: string): Promise&lt;Record&lt;FieldSet&gt;&gt; {  return new Promise((resolve, reject) =&gt; {    base(&amp;#x27;invites&amp;#x27;)      // runs a query on the &amp;#x60;invites&amp;#x60; table      .select({        filterByFormula: &amp;#x60;{invite} = ${escape(inviteCode)}&amp;#x60;,        maxRecords: 1,      })      // reads the first page of results      .firstPage((err, records) =&gt; {        if (err) {          // propagate errors          console.error(err)          return reject(err)        }        // if the record could not be found        // we consider it an error        if (!records || records.length === 0) {          return reject(new Error(&amp;#x27;Invite not found&amp;#x27;))        }        // returns the first record        resolve(records[0])      })  })}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;You might have noticed that this function is almost identical to the &lt;code&gt;getInvite&lt;/code&gt; function we wrote before, we are just returning the raw Airtable record, rather than mapping its data to an &lt;code&gt;Invite&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;So it makes sense to avoid duplication and refactor our &lt;code&gt;getInvite&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getInvite&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteCode&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Invite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;inviteRecord&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getInviteRecord&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteCode&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteRecord&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;fields&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;invite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteRecord&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;fields&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;favouriteColor&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteRecord&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;fields&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;favouriteColor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;weapon&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteRecord&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;fields&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;weapon&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;coming&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#016C9A&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteRecord&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;fields&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;coming&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;undefined&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;undefined&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteRecord&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;fields&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;coming&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;yes&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;export async function getInvite(inviteCode: string): Promise&lt;Invite&gt; {  const inviteRecord = await getInviteRecord(inviteCode)  return {    code: String(inviteRecord.fields.invite),    name: String(inviteRecord.fields.name),    favouriteColor: String(inviteRecord.fields.favouriteColor),    weapon: String(inviteRecord.fields.weapon),    coming:      typeof inviteRecord.fields.coming === &amp;#x27;undefined&amp;#x27;        ? undefined        : inviteRecord.fields.coming === &amp;#x27;yes&amp;#x27;,  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The function is now an &lt;code&gt;async&lt;/code&gt; function. It simply calls our new utility method and performs the mapping to an &lt;code&gt;Invite&lt;/code&gt; object. Pretty simple, right?&lt;/p&gt;
&lt;p&gt;Ok, now we can finally write the utility that allows us to update the &lt;code&gt;coming&lt;/code&gt; field for a given record (by it’s invite code). Let’s call it &lt;code&gt;updateRsvp&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;updateRsvp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;inviteCode&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;rsvp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// gets the raw Airtable id of the record to update&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;getInviteRecord&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteCode&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;reject&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;base&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;invites&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;update&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, { &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;coming&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;rsvp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;yes&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;no&apos;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; }, (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;reject&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;export async function updateRsvp(  inviteCode: string,  rsvp: boolean,): Promise&lt;void&gt; {  // gets the raw Airtable id of the record to update  const { id } = await getInviteRecord(inviteCode)  return new Promise((resolve, reject) =&gt; {    base(&amp;#x27;invites&amp;#x27;).update(id, { coming: rsvp ? &amp;#x27;yes&amp;#x27; : &amp;#x27;no&amp;#x27; }, (err) =&gt; {      if (err) {        return reject(err)      }      resolve()    })  })}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;One thing to remark here is that we are using the Airtable &lt;code&gt;update&lt;/code&gt; method, which allows us to mutate a subset of fields (in our case only the &lt;code&gt;coming&lt;/code&gt; field) and leave unchanged all the other fields. If you’ll ever want to entirely replace a record, well, there’s a &lt;code&gt;replace&lt;/code&gt; method for that!&lt;/p&gt;
&lt;h3 id=&quot;the-rsvp-endpoint&quot;&gt;The RSVP endpoint&lt;/h3&gt;
&lt;p&gt;Now we can put our &lt;code&gt;updateRsvp&lt;/code&gt; utility to good use and expose it through an API endpoint. To do that we can create a new API route by adding the file &lt;code&gt;pages/api/rsvp.ts&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;ts&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;NextApiRequest&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;NextApiResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;next&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;updateRsvp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;../../utils/airtable&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;RequestBody&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;coming&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#AF4238&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;handler&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;NextApiRequest&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;res&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;NextApiResponse&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;&amp;#x3C;{ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;updated&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; } &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; }&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// if the request is not a PUT, return an error&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;method&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!==&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;PUT&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;res&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;405&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Method Not Allowed&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// if the code is missing we return a 400 error&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;res&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;400&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Missing invite code&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;reqBody&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;RequestBody&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// if the code is missing we return a 400 error&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#016C9A&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;reqBody&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;coming&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;undefined&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;res&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;400&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Missing `coming` field in body&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// If there are multiple invite codes (?code=x&amp;#x26;code=y)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// we pick the first one and ignore the rest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;Array&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;isArray&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;code&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;updateRsvp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;reqBody&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;coming&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;res&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;updated&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// In case of error we return either a 401 or a 500 error:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// - if the code was not found we return 401&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// - otherwise we return a generic 500 server error&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Error&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;res&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;status&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Invite not found&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;401&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;500&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; })&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import type { NextApiRequest, NextApiResponse } from &amp;#x27;next&amp;#x27;import { updateRsvp } from &amp;#x27;../../utils/airtable&amp;#x27;type RequestBody = { coming?: boolean }export default async function handler(  req: NextApiRequest,  res: NextApiResponse&lt;{ updated: boolean } | { error: string }&gt;,) {  // if the request is not a PUT, return an error  if (req.method !== &amp;#x27;PUT&amp;#x27;) {    return res.status(405).json({ error: &amp;#x27;Method Not Allowed&amp;#x27; })  }  // if the code is missing we return a 400 error  if (!req.query.code) {    return res.status(400).json({ error: &amp;#x27;Missing invite code&amp;#x27; })  }  const reqBody = req.body as RequestBody  // if the code is missing we return a 400 error  if (typeof reqBody.coming === &amp;#x27;undefined&amp;#x27;) {    return res.status(400).json({ error: &amp;#x27;Missing &amp;#x60;coming&amp;#x60; field in body&amp;#x27; })  }  // If there are multiple invite codes (?code=x&amp;#x26;code=y)  // we pick the first one and ignore the rest  const code = Array.isArray(req.query.code)    ? req.query.code[0]    : req.query.code  try {    await updateRsvp(code, reqBody.coming)    return res.status(200).json({ updated: true })  } catch (err) {    // In case of error we return either a 401 or a 500 error:    // - if the code was not found we return 401    // - otherwise we return a generic 500 server error    const e = err as Error    res      .status(e.message === &amp;#x27;Invite not found&amp;#x27; ? 401 : 500)      .json({ error: e.message })  }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A few things to note here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The API endpoint is now live at &lt;code&gt;http://localhost:3000/api/rsvp&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;This API receives 2 pieces of information: the invite code as a query string parameter and the &lt;code&gt;coming&lt;/code&gt; field in the request body (encoded as a JSON object with just the &lt;code&gt;coming&lt;/code&gt; field).&lt;/li&gt;
&lt;li&gt;This API is a &lt;code&gt;PUT&lt;/code&gt; endpoint. We are receiving some partial data to update a record so it makes sense to use PUT.&lt;/li&gt;
&lt;li&gt;We are not being entirely &lt;em&gt;RESTful&lt;/em&gt; (mostly for simplicity). If we wanted to be &lt;em&gt;RESTful&lt;/em&gt; we should have created a &lt;code&gt;PUT&lt;/code&gt; endpoint on the &lt;code&gt;/api/invite/{code}&lt;/code&gt; path. This is possible in Next.js but it’s slightly more involved, so I went for a simpler solution (since this is a small pet project).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;useinvite-hook-version-2&quot;&gt;&lt;code&gt;useInvite&lt;/code&gt; hook version 2&lt;/h3&gt;
&lt;p&gt;Ok, now that we have an API to update to submit an RSVP, we can update the &lt;code&gt;useInvite&lt;/code&gt; hook to take advantage of this functionality. Be warned: we’ll also be doing some decent amount of refactoring here… Let’s update the &lt;code&gt;useInvite&lt;/code&gt; code in &lt;code&gt;components/hooks/useInvite.tsx&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;tsx&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// adds the URL of the new endpoint&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;RSVP_ENDPOINT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;API_BASE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/rsvp&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// type for the data returned by the hook&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// since we want to return 4 different pieces of information&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// it&apos;s better to organise them in an object, rather tha using&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// an array&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;HookResult&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;inviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;InviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;null&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;null&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;updating&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;boolean&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;updateRsvp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;coming&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Helper function that invokes the rsvp API endpoint&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;updateRsvpRequest&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;code&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;coming&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;Promise&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;requestUrl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;URL&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;RSVP_ENDPOINT&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;requestUrl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;searchParams&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;code&apos;&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fetch&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;requestUrl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;method&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;PUT&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;headers&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Content-Type&apos;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;application/json&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;JSON&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;stringify&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;coming&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; }),&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Failed to update RSVP&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#AF4238&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;useInvite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;HookResult&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;inviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;setInviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;useState&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;InviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;setError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;useState&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// new state field to track when an RSVP update is in progress&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;updating&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;setUpdating&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;useState&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;useEffect&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;URL&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;window&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;location&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;toString&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;searchParams&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;code&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;setError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;No code provided&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;fetchInvite&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;setInviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;setError&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;message&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}, [])&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// new hook function that exposes the ability to update the current invite by&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// providing a value for the `coming` field&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;updateRsvp&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;coming&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;setUpdating&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;updateRsvpRequest&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;inviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;invite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;code&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;coming&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// updates the current invite response, by cloning the original&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// object and updating the `coming` property.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;setInviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;invite&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;inviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;invite&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;coming&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; },&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;setUpdating&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// We return the state variables and the updateRsvp function.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;updating&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;updateRsvp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// ...// adds the URL of the new endpointconst RSVP_ENDPOINT = API_BASE + &amp;#x27;/rsvp&amp;#x27;// type for the data returned by the hook// since we want to return 4 different pieces of information// it&amp;#x27;s better to organise them in an object, rather tha using// an arrayinterface HookResult {  inviteResponse: InviteResponse | null  error: string | null  updating: boolean  updateRsvp: (coming: boolean) =&gt; Promise&lt;void&gt;}// ...// Helper function that invokes the rsvp API endpointasync function updateRsvpRequest(code: string, coming: boolean): Promise&lt;void&gt; {  const requestUrl = new URL(RSVP_ENDPOINT)  requestUrl.searchParams.append(&amp;#x27;code&amp;#x27;, code)  const response = await fetch(requestUrl, {    method: &amp;#x27;PUT&amp;#x27;,    headers: {      &amp;#x27;Content-Type&amp;#x27;: &amp;#x27;application/json&amp;#x27;,    },    body: JSON.stringify({ coming }),  })  if (!response.ok) {    throw new Error(&amp;#x27;Failed to update RSVP&amp;#x27;)  }}export default function useInvite(): HookResult {  const [inviteResponse, setInviteResponse] = useState&lt;InviteResponse | null&gt;(    null,  )  const [error, setError] = useState&lt;string | null&gt;(null)  // new state field to track when an RSVP update is in progress  const [updating, setUpdating] = useState&lt;boolean&gt;(false)  useEffect(() =&gt; {    const url = new URL(window.location.toString())    const code = url.searchParams.get(&amp;#x27;code&amp;#x27;)    if (!code) {      setError(&amp;#x27;No code provided&amp;#x27;)    } else {      fetchInvite(code)        .then(setInviteResponse)        .catch((err) =&gt; {          setError(err.message)        })    }  }, [])  // new hook function that exposes the ability to update the current invite by  // providing a value for the &amp;#x60;coming&amp;#x60; field  async function updateRsvp(coming: boolean) {    if (inviteResponse) {      setUpdating(true)      await updateRsvpRequest(inviteResponse.invite.code, coming)      // updates the current invite response, by cloning the original      // object and updating the &amp;#x60;coming&amp;#x60; property.      setInviteResponse({        ...inviteResponse,        invite: { ...inviteResponse.invite, coming },      })      setUpdating(false)    }  }  // We return the state variables and the updateRsvp function.  return { inviteResponse, error, updating, updateRsvp }}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Some code was omitted. You should have gotten an idea for the main changes, but feel free to check the full content of the file &lt;a href=&quot;https://github.com/lmammino/secret-pizza-party/blob/main/components/hooks/useInvite.tsx&quot;&gt;in the repository&lt;/a&gt; in case you are following along and using this as an hands-on tutorial.&lt;/p&gt;
&lt;h3 id=&quot;using-the-updated-hook&quot;&gt;Using the updated hook&lt;/h3&gt;
&lt;p&gt;I have mixed feelings when it comes to hooks and react. They are sometimes hard to use correctly because of the many rules around them, but to be honest, once you get the gist of them, they are pretty darn convenient.&lt;/p&gt;
&lt;p&gt;In this case, our &lt;code&gt;useInvite&lt;/code&gt; hook can deliver us a lot of value. In fact, it encapsulates all the business logic and lifecycle management to deal with loading and updating invites for the current user. When using this hook in a component, we don’t really have to worry too much about all of these concers: we can literally just access the data and decide when to trigger an update, the hook will handle everything else and trigger a re-render when necessary.&lt;/p&gt;
&lt;p&gt;Let’s see how we can use the hook now. Again, there isn’t much point in showing all our actual code, so let’s observe a simplified example that illustrates the point (you can still &lt;a href=&quot;https://github.com/lmammino/secret-pizza-party/blob/main/components/Home.tsx&quot;&gt;see the complete file in the repository&lt;/a&gt;).&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;tsx&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;React&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;ChangeEvent&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;react&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;useInvite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;./hooks/useInvite&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#AF4238&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;Home&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;() {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// We are now destructuring all the hook attributes and functions&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//  - inviteResponse: the invite response (when available)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//  - error: an error message (if there was an error loading the data)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//  - updating: a boolean that will be true if an update is in progress&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;//  - updateRsvp: the function that allows us to update the current invite (coming or not)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;inviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;updating&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;updateRsvp&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;useInvite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// There was an error loading the data&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;Duh! &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#383A42&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#C71242&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;inviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Still loading the invite data&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;Loading...&lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Utility function to trigger an update when the user&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// checks one of the radio buttons to RSVP&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;onRsvpChange&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;e&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;ChangeEvent&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#885D01&quot;&gt;HTMLInputElement&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4FC1FF;--1:#875D01&quot;&gt;coming&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#016C9A&quot;&gt;===&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;yes&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;updateRsvp&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;coming&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Data loaded correctly: we can display the UI!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; (&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;fieldset&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;disabled&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;updating&lt;/span&gt;&lt;span style=&quot;--0:#569CD6&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;legend&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;Are you coming?&lt;/span&gt;&lt;span style=&quot;--0:#949494&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;legend&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;htmlFor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;yes&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;input&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;radio&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;yes&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;coming&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;yes&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;onChange&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;onRsvpChange&lt;/span&gt;&lt;span style=&quot;--0:#569CD6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;checked&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#569CD6&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;inviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;invite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;coming&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; === &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;/&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;YES&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;htmlFor&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;no&quot;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;input&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;radio&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;no&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;coming&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;no&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;onChange&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#569CD6&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;onRsvpChange&lt;/span&gt;&lt;span style=&quot;--0:#569CD6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;checked&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#569CD6&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;inviteResponse&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;invite&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;coming&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; === &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;/&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;NO&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;label&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;fieldset&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;--0:#949494;--1:#383A42&quot;&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;import React, { ChangeEvent } from &amp;#x27;react&amp;#x27;import useInvite from &amp;#x27;./hooks/useInvite&amp;#x27;// ...export default function Home() {  // We are now destructuring all the hook attributes and functions  //  - inviteResponse: the invite response (when available)  //  - error: an error message (if there was an error loading the data)  //  - updating: a boolean that will be true if an update is in progress  //  - updateRsvp: the function that allows us to update the current invite (coming or not)  const { inviteResponse, error, updating, updateRsvp } = useInvite()  if (error) {    // There was an error loading the data    return &lt;div&gt;Duh! {error}&lt;/div&gt;  }  if (!inviteResponse) {    // Still loading the invite data    return &lt;div&gt;Loading...&lt;/div&gt;  }  // Utility function to trigger an update when the user  // checks one of the radio buttons to RSVP  function onRsvpChange(e: ChangeEvent&lt;HTMLInputElement&gt;) {    const coming = e.target.value === &amp;#x27;yes&amp;#x27;    updateRsvp(coming)  }  // Data loaded correctly: we can display the UI!  return (    &lt;div&gt;      &lt;fieldset disabled={updating}&gt;        &lt;legend&gt;Are you coming?&lt;/legend&gt;        &lt;label htmlFor=&amp;#x22;yes&amp;#x22;&gt;          &lt;input            type=&amp;#x22;radio&amp;#x22;            id=&amp;#x22;yes&amp;#x22;            name=&amp;#x22;coming&amp;#x22;            value=&amp;#x22;yes&amp;#x22;            onChange={onRsvpChange}            checked={inviteResponse.invite.coming === true}          /&gt;          YES        &lt;/label&gt;        &lt;label htmlFor=&amp;#x22;no&amp;#x22;&gt;          &lt;input            type=&amp;#x22;radio&amp;#x22;            id=&amp;#x22;no&amp;#x22;            name=&amp;#x22;coming&amp;#x22;            value=&amp;#x22;no&amp;#x22;            onChange={onRsvpChange}            checked={inviteResponse.invite.coming === false}          /&gt;          NO        &lt;/label&gt;      &lt;/fieldset&gt;    &lt;/div&gt;  )}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note how the two &lt;code&gt;input&lt;/code&gt; have an &lt;code&gt;onChange={onRsvpChange}&lt;/code&gt; to actually trigger the change when the user checks one of the radio buttons. &lt;code&gt;onRsvpChange&lt;/code&gt; will in turn invoke &lt;code&gt;updateRsvp&lt;/code&gt; from the hook, using the value of the selected radio button (&lt;code&gt;&quot;yes&quot;&lt;/code&gt; or &lt;code&gt;&quot;no&quot;&lt;/code&gt; will turn into &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;We also control the input, by specifying &lt;code&gt;checked={inviteResponse.invite.coming === &amp;#x3C;value&gt;}&lt;/code&gt;, so that the input updates accordingly when the data is actually changed by the &lt;code&gt;useInvite&lt;/code&gt; hook.&lt;/p&gt;
&lt;h3 id=&quot;working-app&quot;&gt;Working app&lt;/h3&gt;
&lt;p&gt;At this point we should have a working application!&lt;/p&gt;
&lt;p&gt;One thing that I really like about Airtable is that, when you are looking at a table in their web UI, if the underlying data changes, you’ll see a flash that showcases the change.&lt;/p&gt;
&lt;p&gt;This is a pretty great way to test how our application is actually changing the data in real-time:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Airtable dynamic table update animation&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;800&quot; height=&quot;406&quot; src=&quot;https://loige.co/_astro/airtable-dynamic-table-update-example.C8YBN9ju_ZM6lQs.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Cool, isn’t it? 😎&lt;/p&gt;
&lt;h2 id=&quot;deploying-to-vercel&quot;&gt;Deploying to Vercel&lt;/h2&gt;
&lt;p&gt;Now we have a fully functional application. We are able to get users in only if they have a valid invite code and we can even register their RSVP.&lt;/p&gt;
&lt;p&gt;But all of this is running on our local machine, so how do we put it online?&lt;/p&gt;
&lt;p&gt;Next.js websites can be deployed in a number of places, but being a Vercel product, it should be no surprise the deploying on Vercel is the easiest option (at least for what I have tried).&lt;/p&gt;
&lt;p&gt;This is roughly the list of steps that you should take to deploy on Vercel (from GitHub):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Once you have all your code in a repository on GitHub, you can create an account on &lt;a href=&quot;https://vercel.com/&quot;&gt;Vercel&lt;/a&gt; by logging in using GitHub.&lt;/li&gt;
&lt;li&gt;At this point, you can create a new project (there’s a big button for that) and then select &lt;strong&gt;import Git Repository&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;From that window you should see a list containing all your GitHub repositories.&lt;/li&gt;
&lt;li&gt;Select the repository with your code and cick on &lt;strong&gt;import&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;At this point Vercel will automatically build your code and deploy it, giving you a &lt;strong&gt;.vercel.app&lt;/strong&gt; unique domain.&lt;/li&gt;
&lt;li&gt;If you want, you can also customise the domain and provide a custom one!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What happened behind the scens is that Vercel has deployed all your static assets (HTML, CSS, JavaScript, images,etc) to a CDN and all your API code to a serverless runtime that will be spawn up on demand when new requests arrive.&lt;/p&gt;
&lt;p&gt;The best part is that, once you have done all of this and you have your website online, Vercel has already setup a simple but effective CI/CD workflow for you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Every time you deploy to your &lt;code&gt;main&lt;/code&gt; branch, Vercel will automatically build and release the changes&lt;/li&gt;
&lt;li&gt;If you deploy on another branch, Vercel will deploy and release the changes, but on a temporary URL that you can use to preview your changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt=&quot;Vercel Application dashboard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;986&quot; src=&quot;https://loige.co/_astro/vercel-application-dashboard.8uA2dkGF_ov72C.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;That’s it! You can finally share your invite-only website will all your guests, and I am sure they are going to love it! 😜&lt;/p&gt;
&lt;h2 id=&quot;a-backend-less-alternative-approach&quot;&gt;A backend-less alternative approach&lt;/h2&gt;
&lt;p&gt;Before we wrap up, I want to give a quick mention to an idea I had while I was writing this post.&lt;/p&gt;
&lt;p&gt;If we relax a bit our requirements removing the fact that we might want to collect user data (RSVP), there migth be a &lt;em&gt;“backend-less”&lt;/em&gt; alternative implementation.&lt;/p&gt;
&lt;p&gt;Rather than using random invite codes, we could, in fact, use &lt;a href=&quot;/whats-in-a-jwt&quot;&gt;JSON Web Tokens&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We could embed all the necessary information into the token paylos:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;❯&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;jwtinfo&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiTGVvbmFyZG8iLCJmYXZvdXJpdGVDb2xvciI6ImJsdWUiLCJ3ZWFwb24iOiJUd2luIEthdGFuYSJ9.Ac69w5qHwnpzX3DZX4np-AZxcYcUA2D1aW64O2wB53v277MmamEuALJp6un2LTkYAeyciCz8eY6bRMNf9tq9e_KRAZcznffZf-vNUnzaWh9TgFhKuEdn2kI8B4d4NBP0TSW6iq-PLNVfwzldjilYA-QJRevcztSmcc-cEpZHukQdUHjy&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; | &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;jq&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;&quot;favouriteColor&quot;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;blue&quot;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Leonardo&quot;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;&quot;weapon&quot;&lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#016C9A&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Twin Katana&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;❯ jwtinfo &amp;#x22;eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiTGVvbmFyZG8iLCJmYXZvdXJpdGVDb2xvciI6ImJsdWUiLCJ3ZWFwb24iOiJUd2luIEthdGFuYSJ9.Ac69w5qHwnpzX3DZX4np-AZxcYcUA2D1aW64O2wB53v277MmamEuALJp6un2LTkYAeyciCz8eY6bRMNf9tq9e_KRAZcznffZf-vNUnzaWh9TgFhKuEdn2kI8B4d4NBP0TSW6iq-PLNVfwzldjilYA-QJRevcztSmcc-cEpZHukQdUHjy&amp;#x22; | jq .{  &amp;#x22;favouriteColor&amp;#x22;: &amp;#x22;blue&amp;#x22;,  &amp;#x22;name&amp;#x22;: &amp;#x22;Leonardo&amp;#x22;,  &amp;#x22;weapon&amp;#x22;: &amp;#x22;Twin Katana&amp;#x22;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Yes, you should totally check out &lt;a href=&quot;/learning-rust-through-open-source-and-live-code-reviews&quot;&gt;the story of this cool &lt;code&gt;jwtinfo&lt;/code&gt; command&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;The JWT signature should be generated using an asymmetric algorithm like &lt;code&gt;ES512&lt;/code&gt;. At that point the frontend could embed the public key and use it to validate tokens and decide to show the information or not.&lt;/p&gt;
&lt;p&gt;This would a be a very simple approach and it’s not free from flaws, for example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All the information needs to be embedded in the token&lt;/li&gt;
&lt;li&gt;You won’t have a way to fetch private information from an API, so you are forced to put more stuff into the token or end up leaking sensitive information in your JavaScript bundle&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Still this simple approach might be good enough for simple websites that might be building for your friends and family!&lt;/p&gt;
&lt;p&gt;Plus, you’d get to use JWT, which is a cool technology! 😜&lt;/p&gt;
&lt;p&gt;As always, keep in mind that in technology there isn’t a perfect solution, just a different set of tradeoffs!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this post we learned how to build an invite only Single Page Application using Next.js and Airtable as a data storage layer.&lt;/p&gt;
&lt;p&gt;In the process we also saw how to create backend APIs with Next.js, how to create custom hook to simplify data fetching and update from the frontend and how to deploy our final creation to Vercel.&lt;/p&gt;
&lt;p&gt;I am curious to know what you think about this approach and if you are thinking to use this for some personal or work projects.&lt;/p&gt;
&lt;p&gt;Do let me know in the comments and, if you found this post valuable, consider &lt;a href=&quot;https://twitter.com/loige&quot;&gt;following me on Twitter&lt;/a&gt; and sharing this article!&lt;/p&gt;
&lt;p&gt;Thank you and see you in the next article! 👋&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/invite-only-microsites-with-nextjs-and-airtable.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/invite-only-microsites-with-nextjs-and-airtable.png" width="1200" height="630"/></media:content><category>javascript</category><category>typescript</category><category>react</category><category>nextjs</category><category>jwt</category><author>Luciano Mammino</author><comments>https://loige.co/invite-only-microsites-with-nextjs-and-airtable/#comments</comments><enclosure url="https://loige.co/og/invite-only-microsites-with-nextjs-and-airtable.png" length="0" type="image/png"/></item><item><title>Debugging custom ApiGateway authorizers</title><link>https://loige.co/debugging-custom-apigateway-authorizers/</link><guid isPermaLink="true">https://loige.co/debugging-custom-apigateway-authorizers/</guid><description>When building a custom API Gateway authorizer, mysterious 500 errors can happen. This post shows how to enable CloudWatch logging for API Gateway to inspect the logs and debug problems.</description><pubDate>Sun, 05 Nov 2023 13:48:00 GMT</pubDate><content:encoded>&lt;p&gt;Last week, while working on &lt;a href=&quot;https://github.com/lmammino/oidc-authorizer&quot;&gt;a custom REST API Gateway Lambda authorizer&lt;/a&gt;, I spent some time trying to debug a mysterious &lt;code&gt;500&lt;/code&gt; error with a &lt;code&gt;{&quot;message&quot;:null}&lt;/code&gt; body. In this article, I will share why this was happening and how to debug this kind of error when building custom API Gateway authorizers.&lt;/p&gt;
&lt;h2 id=&quot;the-use-case&quot;&gt;The use case&lt;/h2&gt;
&lt;p&gt;Before diving into the problem, let me give you a bit of context about the use case I was working on. As I said, I was working on an open-source project implementing a custom authorizer for AWS API Gateway. The project is simply called &lt;a href=&quot;https://github.com/lmammino/oidc-authorizer&quot;&gt;&lt;code&gt;oidc-authorizer&lt;/code&gt;&lt;/a&gt; and it’s already available on GitHub and the &lt;a href=&quot;https://serverlessrepo.aws.amazon.com/applications/eu-west-1/795006566846/oidc-authorizer&quot;&gt;Serverless Application Repository (SAR)&lt;/a&gt;. This authorizer is implemented as a Lambda function and it allows you to authenticate requests following to OIDC (OpenID Connect) protocol.&lt;/p&gt;
&lt;p&gt;To better understand what that means, let’s have a look at this lovely diagram (that I am proud to have drawn by myself):&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A sketchy diagram with a user that sends an authenticated request to API Gateway. API Gateway is configured to use a custom lambda as an authorizer (implemented by the oidc-authorizer project). The lambda talks with your OIDC provider to get the public key to validate the user token and responds to API Gateway to Allow or Deny the request.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1000&quot; height=&quot;648&quot; src=&quot;https://loige.co/_astro/diagram-from-oidc-authorizer.DsfWLTZO_Z2l8HxD.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;In this diagram, we see a user that sends an authenticated request to API Gateway. API Gateway is configured to use a lambda as a custom authorizer. The lambda talks with a given OIDC provider to get the public key to validate the user token and responds to API Gateway to Allow or Deny the request.&lt;/p&gt;
&lt;p&gt;This type of authentication is based on the idea that a token (in this case, a &lt;em&gt;JWT&lt;/em&gt;) can be trusted only if it’s signed by an authority we trust. That’s why we need to talk with the OIDC provider to get the public key to validate the signature of the token.&lt;/p&gt;
&lt;p&gt;I have been speaking and writing at length about &lt;a href=&quot;/tag/jwt&quot;&gt;JWT&lt;/a&gt; before, so I am just going to say that if you want to deep dive into the fascinating topic of OIDC you can check out the &lt;a href=&quot;https://openid.net/specs/openid-connect-core-1_0.html&quot;&gt;official specification of the OIDC standard&lt;/a&gt;. If you have the guts to read protocol specifications, it’s a very interesting read, I promise! 😇&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The problem&lt;/h2&gt;
&lt;p&gt;Ok, all pretty cool, but what was the problem?&lt;/p&gt;
&lt;p&gt;The problem is that I am a terrible programmer and when I started testing my first version of the authorizer my code was quite buggy and it didn’t work in the way that REST API Gateway Authorizers are supposed to work.&lt;/p&gt;
&lt;p&gt;I take responsibility for that, but that’s only part of the problem. The other side of the coin is that AWS wasn’t really giving me a useful error message: the only thing I could see when making a request was a &lt;code&gt;500&lt;/code&gt; error with a response body containing only the JSON payload &lt;code&gt;{&quot;message&quot;:null}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;The response that is received by a borked custom REST API Gateway authorizer. You get just a 500 with a message: null payload&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1162&quot; height=&quot;604&quot; src=&quot;https://loige.co/_astro/lambda-authorizer-returning-a-500-null-error.CnAnZehn_Z12ftMw.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;The full response:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;HTTP/2 500&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;content-type: application/json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;content-length: 16&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;date: Sat, 04 Nov 2023 12:13:50 GMT&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amzn-requestid: [...]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amzn-errortype: AuthorizerConfigurationException&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amz-apigw-id: w218poymg7&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-cache: Error from cloudfront&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;via: 1.1 [...]cloudfront.net (CloudFront)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amz-cf-pop: [...]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amz-cf-id: [...]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;{&quot;message&quot;:null}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;HTTP/2 500content-type: application/jsoncontent-length: 16date: Sat, 04 Nov 2023 12:13:50 GMTx-amzn-requestid: [...]x-amzn-errortype: AuthorizerConfigurationExceptionx-amz-apigw-id: w218poymg7x-cache: Error from cloudfrontvia: 1.1 [...]cloudfront.net (CloudFront)x-amz-cf-pop: [...]x-amz-cf-id: [...]{&amp;#x22;message&amp;#x22;:null}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Shrugh… What do you do in these cases? 🤷&lt;/p&gt;
&lt;p&gt;You try to look for some logs in CloudWatch, right? Well, I did that and I found nothing. API Gateway doesn’t have a log group by default and I was expecting to see some logs from my Lambda function, but there was nothing useful there!&lt;/p&gt;
&lt;h2 id=&quot;the-solution&quot;&gt;The solution&lt;/h2&gt;
&lt;p&gt;The solution is to enable extensive logging for API Gateway.&lt;/p&gt;
&lt;p&gt;So, how do we do that?&lt;/p&gt;
&lt;p&gt;We can do that using Infrastructure as code using CloudFormation or SAM.&lt;/p&gt;
&lt;p&gt;These are the logical steps we need to follow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a Role that allows API Gateway (at the service level) to write logs to CloudWatch&lt;/li&gt;
&lt;li&gt;Use the &lt;a href=&quot;https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-account.html&quot;&gt;&lt;code&gt;AWS::ApiGateway::Account&lt;/code&gt;&lt;/a&gt; resource to assign the role we just created to API Gateway.&lt;/li&gt;
&lt;li&gt;Updated the specific instance of a REST API Gateway stage to enable logging and tracing on it.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;enabling-api-gateway-logging-to-cloudwatch-with-cloudformation&quot;&gt;Enabling API Gateway logging to CloudWatch with CloudFormation&lt;/h2&gt;
&lt;p&gt;OK, let’s start with the code for the first 2 steps using the following CloudFormation template:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;apigw-logging.yaml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;AWSTemplateFormatVersion&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;2010-09-09&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Description&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;Allow API Gateway to write logs to CloudWatch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Resources&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;ApiCWLRoleArn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;AWS::ApiGateway::Account&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Properties&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;CloudWatchRoleArn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;!GetAtt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;CloudWatchRole.Arn&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;CloudWatchRole&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;AWS::IAM::Role&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Properties&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;AssumeRolePolicyDocument&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Version&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;2012-10-17&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Statement&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Action&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;sts:AssumeRole&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Effect&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;Allow&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Principal&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Service&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;apigateway.amazonaws.com&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Path&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;ManagedPolicyArns&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;AWSTemplateFormatVersion: &amp;#x27;2010-09-09&amp;#x27;Description: Allow API Gateway to write logs to CloudWatchResources:  ApiCWLRoleArn:    Type: AWS::ApiGateway::Account    Properties:      CloudWatchRoleArn: !GetAtt CloudWatchRole.Arn  CloudWatchRole:    Type: AWS::IAM::Role    Properties:      AssumeRolePolicyDocument:        Version: &amp;#x27;2012-10-17&amp;#x27;        Statement:          Action: &amp;#x27;sts:AssumeRole&amp;#x27;          Effect: Allow          Principal:            Service: apigateway.amazonaws.com      Path: /      ManagedPolicyArns:        - &amp;#x27;arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs&amp;#x27;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;To avoid overwriting other roles, we should only have one &lt;code&gt;AWS::ApiGateway::Account&lt;/code&gt; resource per region per account, so we are creating a generic stack only to allow API Gateway to send logs to CloudWatch. We will be defining our APIs in other stacks.&lt;/p&gt;
&lt;p&gt;Let’s say we call this file &lt;code&gt;apigw-logging.yaml&lt;/code&gt;. We can now deploy it with the following command:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;aws&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;cloudformation&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;deploy&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--template-file&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;apigw-logging.yaml&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--stack-name&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;apigw-logging&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D7BA7D;--1:#016C9A&quot;&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--capabilities&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;CAPABILITY_IAM&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;aws cloudformation deploy \  --template-file apigw-logging.yaml \  --stack-name apigw-logging \  --capabilities CAPABILITY_IAM&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Make sure to specify a region either with the &lt;code&gt;--region&lt;/code&gt; flag or by setting the &lt;code&gt;AWS_DEFAULT_REGION&lt;/code&gt; environment variable.&lt;/p&gt;
&lt;p&gt;If all goes well, you should see an output like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Waiting for changeset to be created..&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Waiting for stack create/update to complete&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Successfully created/updated stack - apigw-logging&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Waiting for changeset to be created..Waiting for stack create/update to completeSuccessfully created/updated stack - apigw-logging&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: if you prefer to use SAM (which we will use later), you can use it to deploy the template above with the following command: &lt;code&gt;sam deploy --guided --template apigw-logging.yaml&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;enable-logging-and-tracing-for-a-specific-api-gateway-stage-using-sam&quot;&gt;Enable logging and tracing for a specific API Gateway stage using SAM&lt;/h2&gt;
&lt;p&gt;Now that we have a role that allows API Gateway to write logs to CloudWatch, we can enable logging and tracing for a specific API Gateway stage.&lt;/p&gt;
&lt;p&gt;This time, to make our life a bit easier, we prefer to use &lt;a href=&quot;https://aws.amazon.com/serverless/sam/&quot;&gt;SAM&lt;/a&gt; (rather than CloudFormation) to define our API Gateway. SAM is a superset of CloudFormation that allows us to define serverless applications more concisely.&lt;/p&gt;
&lt;p&gt;So, let’s say we have another SAM template that defines an API Gateway and the stage we want to enable logging. The template could look like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;api.yaml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;AWSTemplateFormatVersion&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;2010-09-09&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Transform&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;AWS::Serverless-2016-10-31&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Description&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;AWS SAM template with a simple API definition&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Resources&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;ApiGatewayApi&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;AWS::Serverless::Api&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Properties&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;StageName&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;prod&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Description&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;Our production API&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# Enable traces and logs for the API Gateway stage&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;TracingEnabled&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;MethodSettings&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;- &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;HttpMethod&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;LoggingLevel&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;INFO&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;ResourcePath&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;/*&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;MetricsEnabled&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;DataTraceEnabled&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# A sample API endpoint backed by a Lambda function&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;SampleApiFunction1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;AWS::Serverless::Function&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Properties&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Events&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;ApiEvent&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;Api&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Properties&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Path&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;/hello&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Method&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;get&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;RestApiId&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Ref&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;ApiGatewayApi&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Runtime&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;python3.9&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Handler&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;index.handler&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;InlineCode&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;|&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;def handler(event, context):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;return {&apos;body&apos;: &apos;Hello, my friend!&apos;, &apos;statusCode&apos;: 200}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# Prints the full URL of our test endpoint&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Outputs&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;HelloEndpoint&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Description&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;API Gateway endpoint&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;!Sub&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;https://${ApiGatewayApi}.execute-api.${AWS::Region}.amazonaws.com/prod/hello&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;AWSTemplateFormatVersion: &amp;#x27;2010-09-09&amp;#x27;Transform: AWS::Serverless-2016-10-31Description: AWS SAM template with a simple API definitionResources:  ApiGatewayApi:    Type: AWS::Serverless::Api    Properties:      StageName: prod      Description: Our production API      # Enable traces and logs for the API Gateway stage      TracingEnabled: true      MethodSettings:        - HttpMethod: &amp;#x27;*&amp;#x27;          LoggingLevel: INFO          ResourcePath: &amp;#x27;/*&amp;#x27;          MetricsEnabled: true          DataTraceEnabled: true  # A sample API endpoint backed by a Lambda function  SampleApiFunction1:    Type: AWS::Serverless::Function    Properties:      Events:        ApiEvent:          Type: Api          Properties:            Path: /hello            Method: get            RestApiId:              Ref: ApiGatewayApi      Runtime: python3.9      Handler: index.handler      InlineCode: |        def handler(event, context):            return {&amp;#x27;body&amp;#x27;: &amp;#x27;Hello, my friend!&amp;#x27;, &amp;#x27;statusCode&amp;#x27;: 200}# Prints the full URL of our test endpointOutputs:  HelloEndpoint:    Description: &amp;#x27;API Gateway endpoint&amp;#x27;    Value: !Sub &amp;#x27;https://${ApiGatewayApi}.execute-api.${AWS::Region}.amazonaws.com/prod/hello&amp;#x27;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Let’s deploy this stack with:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sam&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;deploy&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--guided&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--template&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;api.yaml&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sam deploy --guided --template api.yaml&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note that SAM will warn us that we haven’t set any authorization for our API Gateway. That’s fine for now, we will add it later. But you need to make sure you reply &lt;code&gt;Y&lt;/code&gt; to the following question:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;SampleApiFunction1 has no authentication. Is this okay?&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;SampleApiFunction1 has no authentication. Is this okay?&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If all goes well, you should see an output containing the URL of our endpoint. If you call it you should see the message: &lt;em&gt;“Hello, my friend!”&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;adding-a-custom-authorizer-to-our-api-gateway&quot;&gt;Adding a custom authorizer to our API Gateway&lt;/h2&gt;
&lt;p&gt;Now that we have an API Gateway with a stage that has logging and tracing enabled, we can add a custom authorizer to it.&lt;/p&gt;
&lt;p&gt;The goal of this article is not to deep dive into how to write a custom API Gateway authorizer. If you want a deep dive into that, I warmly recommend this fantastic article by &lt;a href=&quot;https://twitter.com/alexbdebrie&quot;&gt;Alex DeBrie&lt;/a&gt;: &lt;a href=&quot;https://www.alexdebrie.com/posts/lambda-custom-authorizers/&quot;&gt;“The Complete Guide to Custom Authorizers with AWS Lambda and API Gateway”&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Just to have a simple example to work with, let’s say that we want to authorise all requests that provide an &lt;code&gt;Authorization&lt;/code&gt; header that contains an odd number.&lt;/p&gt;
&lt;p&gt;So the following headers will be authorized: ✅&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Authorization: 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Authorization: 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Authorization: 5&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Authorization: 1Authorization: 3Authorization: 5...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;While, the following headers will be denied: ❌&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Authorization: 2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Authorization: 4&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Authorization: something else&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Authorization: 2Authorization: 4...Authorization: something else&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Even failing to pass the &lt;code&gt;Authorization&lt;/code&gt; header will result in a denial.&lt;/p&gt;
&lt;p&gt;The code for our custom Authorizer could look like this (don’t judge my terrible Python skillz, pleaze 😅):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;handler.py&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;handler&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#875D01&quot;&gt;event&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--1:#875D01&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE&quot;&gt;context&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;):&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;authorization_token = event[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;authorizationToken&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;endpoint = event[&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;methodArn&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(authorization_token) % &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; == &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# valid authorization response&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;principalId&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;authenticatedUser&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;policyDocument&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Version&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;2012-10-17&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Statement&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Action&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;execute-api:Invoke&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Allow&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;              &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;except&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;pass&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# deny response&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#C586C0;--1:#A626A4&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;policyDocument&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Version&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;2012-10-17&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Statement&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Action&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;execute-api:Invoke&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Deny&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;(endpoint)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;def handler(event, context):  authorization_token = event[&amp;#x27;authorizationToken&amp;#x27;]  endpoint = event[&amp;#x27;methodArn&amp;#x27;]  try:    if int(authorization_token) % 2 == 1:      # valid authorization response      return {        &amp;#x22;principalId&amp;#x22;: &amp;#x22;authenticatedUser&amp;#x22;,        &amp;#x22;policyDocument&amp;#x22;: {          &amp;#x22;Version&amp;#x22;: &amp;#x22;2012-10-17&amp;#x22;,          &amp;#x22;Statement&amp;#x22;: [            {              &amp;#x22;Action&amp;#x22;: &amp;#x22;execute-api:Invoke&amp;#x22;,              &amp;#x22;Effect&amp;#x22;: &amp;#x22;Allow&amp;#x22;,              &amp;#x22;Resource&amp;#x22;: &amp;#x22;*&amp;#x22;            }          ]        }      }  except:    pass  # deny response  return {    &amp;#x22;policyDocument&amp;#x22;: {      &amp;#x22;Version&amp;#x22;: &amp;#x22;2012-10-17&amp;#x22;,      &amp;#x22;Statement&amp;#x22;: [        {          &amp;#x22;Action&amp;#x22;: &amp;#x22;execute-api:Invoke&amp;#x22;,          &amp;#x22;Effect&amp;#x22;: &amp;#x22;Deny&amp;#x22;,          &amp;#x22;Resource&amp;#x22;: str(endpoint)        }      ],    }  }&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If you save this Python code in a file called &lt;code&gt;handler.py&lt;/code&gt; in the same folder where we have our &lt;code&gt;api.yaml&lt;/code&gt; template, then we can add the authorizer to the template like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;api.yaml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Resources&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# [...]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# Authorizer Lambda&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;SimpleApiAuthorizerLambda&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;AWS::Serverless::Function&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Properties&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Runtime&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;python3.9&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Handler&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;handler.handler&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;CodeUri&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#B5CEA8;--1:#875D01&quot;&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Resources:  # [...]  # Authorizer Lambda  SimpleApiAuthorizerLambda:    Type: AWS::Serverless::Function    Properties:      Runtime: python3.9      Handler: handler.handler      CodeUri: .&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This only creates the Lambda resource, but to configure it as an authorizer, we need to add the following section to the &lt;code&gt;ApiGatewayApi&lt;/code&gt; resource:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;api.yaml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Resources&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# [...]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;ApiGatewayApi&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;AWS::Serverless::Api&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;    &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Properties&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# [...]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;      &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Auth&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;DefaultAuthorizer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;SimpleApiAuthorizer&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;        &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;Authorizers&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;          &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;SimpleApiAuthorizer&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;FunctionPayloadType&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;REQUEST&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;            &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#AF4238&quot;&gt;FunctionArn&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;!GetAtt&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;SimpleApiAuthorizerLambda.Arn&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Resources:  # [...]  ApiGatewayApi:    Type: AWS::Serverless::Api    Properties:      # [...]      Auth:        DefaultAuthorizer: SimpleApiAuthorizer        Authorizers:          SimpleApiAuthorizer:            FunctionPayloadType: REQUEST            FunctionArn: !GetAtt SimpleApiAuthorizerLambda.Arn&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Ok, we are finally ready to deploy our updates to the &lt;code&gt;api.yaml&lt;/code&gt; template with:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;sam&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;deploy&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--guided&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--template&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;api.yaml&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;sam deploy --guided --template api.yaml&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If all went well, we should now be ready to send requests to our API Gateway and see the authorizer in action.&lt;/p&gt;
&lt;p&gt;Let’s try to send a request with a valid authorization header:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-i&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-X&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;GET&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;-H&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;Authorization: 17&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;your-api-url&gt;/hello&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;curl -i -X GET -H &amp;#x27;Authorization: 17&amp;#x27; &lt;your-api-url&gt;/hello&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;You should see a response like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;HTTP/2 200&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;content-type: application/json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;content-length: 21&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;date: Sun, 05 Nov 2023 13:24:15 GMT&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amzn-requestid: 7a8c5040-e76b-400f-8407-0c6ed9b72e46&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amz-apigw-id: N7Sb5GwpDoEEf9A=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amzn-trace-id: Root=1-6547977f-2ec69acd4fd64cb0285e36d7&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-cache: Miss from cloudfront&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;via: 1.1 33388636a7cb2afa812b276d900f88d4.cloudfront.net (CloudFront)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amz-cf-pop: DUB56-P1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amz-cf-id: DOa6otRm_gZyYG0rn-FM-vC1HhjzuhJIAzfms02bbny_0DpmKMTc3w==&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Hello, my friend!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;HTTP/2 200content-type: application/jsoncontent-length: 21date: Sun, 05 Nov 2023 13:24:15 GMTx-amzn-requestid: 7a8c5040-e76b-400f-8407-0c6ed9b72e46x-amz-apigw-id: N7Sb5GwpDoEEf9A=x-amzn-trace-id: Root=1-6547977f-2ec69acd4fd64cb0285e36d7x-cache: Miss from cloudfrontvia: 1.1 33388636a7cb2afa812b276d900f88d4.cloudfront.net (CloudFront)x-amz-cf-pop: DUB56-P1x-amz-cf-id: DOa6otRm_gZyYG0rn-FM-vC1HhjzuhJIAzfms02bbny_0DpmKMTc3w==Hello, my friend!&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If instead we send a request without an &lt;code&gt;Authorization&lt;/code&gt; header we should see something like:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;HTTP/2 401&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;content-type: application/json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;content-length: 26&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;date: Sun, 05 Nov 2023 13:25:29 GMT&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amzn-requestid: e9ab5f97-9a5a-4f34-94d7-87df74a235de&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amzn-errortype: UnauthorizedException&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amz-apigw-id: N7SnfFYZjoEEolg=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amzn-trace-id: Root=1-654797c9-3cd1a8f5095fef3e3297ac26&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-cache: Error from cloudfront&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;via: 1.1 93951ac7649a5f7c158d327385b2aeb8.cloudfront.net (CloudFront)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amz-cf-pop: DUB56-P1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amz-cf-id: PuyPcm7sY13bfhigJXgNGTgYkT5CjinaK_uD6bl0jDNdGn_U0_pmHw==&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;{&quot;message&quot;:&quot;Unauthorized&quot;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;HTTP/2 401content-type: application/jsoncontent-length: 26date: Sun, 05 Nov 2023 13:25:29 GMTx-amzn-requestid: e9ab5f97-9a5a-4f34-94d7-87df74a235dex-amzn-errortype: UnauthorizedExceptionx-amz-apigw-id: N7SnfFYZjoEEolg=x-amzn-trace-id: Root=1-654797c9-3cd1a8f5095fef3e3297ac26x-cache: Error from cloudfrontvia: 1.1 93951ac7649a5f7c158d327385b2aeb8.cloudfront.net (CloudFront)x-amz-cf-pop: DUB56-P1x-amz-cf-id: PuyPcm7sY13bfhigJXgNGTgYkT5CjinaK_uD6bl0jDNdGn_U0_pmHw=={&amp;#x22;message&amp;#x22;:&amp;#x22;Unauthorized&amp;#x22;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Finally, if we send an invalid value for the &lt;code&gt;Authorization&lt;/code&gt; header (e.g. not a number or an even number) we should see something like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;HTTP/2 403&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;content-type: application/json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;content-length: 82&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;date: Sun, 05 Nov 2023 13:26:18 GMT&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amzn-requestid: 49a6b913-a965-4f66-a9e1-7b4ccf3b96cc&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amzn-errortype: AccessDeniedException&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amz-apigw-id: N7SvJHWQDoEEXeA=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amzn-trace-id: Root=1-654797fa-6ae95da234f15ba6587fb36d&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-cache: Error from cloudfront&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;via: 1.1 4b0861a8035fd11b1a90183c566020e2.cloudfront.net (CloudFront)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amz-cf-pop: DUB56-P1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;x-amz-cf-id: gA-hS_7NeRjCtmKPc2P76uGyxaDNmWpE8iUZQMsxMHBoWm2W4uTPqw==&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;{&quot;Message&quot;:&quot;User is not authorized to access this resource with an explicit deny&quot;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;HTTP/2 403content-type: application/jsoncontent-length: 82date: Sun, 05 Nov 2023 13:26:18 GMTx-amzn-requestid: 49a6b913-a965-4f66-a9e1-7b4ccf3b96ccx-amzn-errortype: AccessDeniedExceptionx-amz-apigw-id: N7SvJHWQDoEEXeA=x-amzn-trace-id: Root=1-654797fa-6ae95da234f15ba6587fb36dx-cache: Error from cloudfrontvia: 1.1 4b0861a8035fd11b1a90183c566020e2.cloudfront.net (CloudFront)x-amz-cf-pop: DUB56-P1x-amz-cf-id: gA-hS_7NeRjCtmKPc2P76uGyxaDNmWpE8iUZQMsxMHBoWm2W4uTPqw=={&amp;#x22;Message&amp;#x22;:&amp;#x22;User is not authorized to access this resource with an explicit deny&amp;#x22;}&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note how there’s a difference in the error response between not sending an &lt;code&gt;Authorization&lt;/code&gt; header and sending an invalid one. In the first case, we get a &lt;code&gt;401&lt;/code&gt; with a &lt;code&gt;{&quot;message&quot;:&quot;Unauthorized&quot;}&lt;/code&gt; body, while in the second case, we get a &lt;code&gt;403&lt;/code&gt; with a &lt;code&gt;{&quot;Message&quot;:&quot;User is not authorized to access this resource with an explicit deny&quot;}&lt;/code&gt; body.&lt;/p&gt;
&lt;p&gt;In the first case, API Gateway is automatically handling the response for us and our custom authorizer lambda is not even invoked. In the second case, the authorizer is invoked and it returns a &lt;code&gt;Deny&lt;/code&gt; response, which produces a &lt;code&gt;403&lt;/code&gt; error and that specific error message.&lt;/p&gt;
&lt;h2 id=&quot;looking-at-the-api-gateway-logs&quot;&gt;Looking at the API Gateway logs&lt;/h2&gt;
&lt;p&gt;Ok, I have been kind enough to give you a working authorizer, so we didn’t really have to debug much… but we should still have a look at the API Gateway logs to see what they look like and why they could be really useful in case something went wrong and we needed to troubleshoot.&lt;/p&gt;
&lt;p&gt;To look at the logs, we need to go to the &lt;a href=&quot;https://console.aws.amazon.com/cloudwatch/&quot;&gt;CloudWatch console&lt;/a&gt;. From there, we need to select the &lt;code&gt;Logs&lt;/code&gt; section and then the &lt;code&gt;Log groups&lt;/code&gt; section. We should see a list of log groups and we should be able to find the one for our API Gateway. It should be called something like &lt;code&gt;API-Gateway-Execution-Logs_&amp;#x3C;your-api-id&gt;/prod&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Example of API Gateway logs&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;1620&quot; height=&quot;1656&quot; src=&quot;https://loige.co/_astro/example-of-api-gateway-logs-with-custom-authorizer.C3XmxMxU_Z2wUfwg.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;As you can see, in these logs you can see quite a bit of detail about all the steps that API Gateway is performing before and after invoking our custom authorizer. This is really useful to understand what’s going on and where the problem could be.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;And this brings us to the end of this article!&lt;/p&gt;
&lt;p&gt;I hope you enjoyed it and that you learned something new.&lt;/p&gt;
&lt;p&gt;If you have any questions or feedback, please let me know in the &lt;a href=&quot;#comments&quot;&gt;comments&lt;/a&gt; below or on &lt;a href=&quot;https://twitter.com/loige&quot;&gt;X, formerly Twitter&lt;/a&gt;.&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/debugging-custom-apigateway-authorizers.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/debugging-custom-apigateway-authorizers.png" width="1200" height="630"/></media:content><category>aws</category><category>serverless</category><category>lambda</category><category>api-gateway</category><author>Luciano Mammino</author><comments>https://loige.co/debugging-custom-apigateway-authorizers/#comments</comments><enclosure url="https://loige.co/og/debugging-custom-apigateway-authorizers.png" length="0" type="image/png"/></item><item><title>Building x86 Rust containers from Mac Silicon</title><link>https://loige.co/building_x86_rust-containers-from-mac-silicon/</link><guid isPermaLink="true">https://loige.co/building_x86_rust-containers-from-mac-silicon/</guid><description>This article walks through the challenges of cross-compiling a Rust web app from a Mac Silicon machine to an x86 Docker container using musl, RusTLS, multi-stage builds and other techniques to produce a small container image.</description><pubDate>Fri, 05 May 2023 09:29:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently struggled to build an x86_64 container for a web app written in Rust from my Mac Silicon. I eventually figured out a working solution that also heavily reduced the size of the container image. In this article, I will walk you through this solution!&lt;/p&gt;
&lt;p&gt;This solution involves a bunch of interesting technology, so if nothing else, it’s going to be an opportunity to explore these cool topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/tag/rust&quot;&gt;Rust&lt;/a&gt; (of course)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/tag/docker&quot;&gt;Docker&lt;/a&gt; (of course)&lt;/li&gt;
&lt;li&gt;Docker multi-stage builds&lt;/li&gt;
&lt;li&gt;Linux Alpine&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://musl.libc.org/&quot;&gt;musl libc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.qemu.org/&quot;&gt;QEMU&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rustls/rustls&quot;&gt;RusTLS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jemalloc.net/&quot;&gt;Jemalloc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The big disclaimer is that I am not sure this is the best solution ever, but it’s definitely “a solution”. If you have been through the same journey and you think there’s something that can be improved, I’d love to hear that! After all, we are here to learn from each other, so do reach out &lt;a href=&quot;https://twitter.com/loige&quot;&gt;on Twitter&lt;/a&gt; or &lt;a href=&quot;#comments&quot;&gt;in the comments below&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-use-case&quot;&gt;The use case&lt;/h2&gt;
&lt;p&gt;Let’s start by putting things in context. What’s the problem I am trying to solve here anyway?&lt;/p&gt;
&lt;p&gt;I built a web application using &lt;a href=&quot;https://github.com/tokio-rs/axum&quot;&gt;Axum&lt;/a&gt; (a cool Rust web framework) and &lt;a href=&quot;https://www.solidjs.com/&quot;&gt;SolidJS&lt;/a&gt; (which, as an aside, is becoming my favourite frontend JavaScript framework).&lt;/p&gt;
&lt;p&gt;The app works and I am happy with it. &lt;em&gt;It works on my machine™️&lt;/em&gt;, but now the question is &lt;em&gt;“How do I ship it to production?”&lt;/em&gt; 🛳️&lt;/p&gt;
&lt;p&gt;In this particular case, I don’t have too much of a say on how to structure the production environment, what I am told is that &lt;strong&gt;I get to run “a container” in some kind of Virtual Private Server somewhere&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So no AWS joy, for me, this time around 🥲 … but life is good, at least I can still use containers, which should be easy enough, right? RIGHT?! 🥺&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;How hard it can be? (Spongebob)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;480&quot; height=&quot;360&quot; src=&quot;https://loige.co/_astro/hard.BvLwDVOp_ZxUsKn.webp&quot; &gt;&lt;/p&gt;
&lt;h2 id=&quot;the-first-attempt&quot;&gt;The first attempt&lt;/h2&gt;
&lt;p&gt;So, being able to ship a Docker container, I don’t really have to know much about the target environment. I am guaranteed I will have enough memory and CPU for my container and that (critical piece of information) the VPS runs on a &lt;strong&gt;x86 64 bits processor&lt;/strong&gt;. So I have to make sure to provide a container for this target architecture.&lt;/p&gt;
&lt;p&gt;Another critical piece of information is that my development machine is a Mac with a silicon processor, so I need to figure out how to build my container for a different architecture.&lt;/p&gt;
&lt;p&gt;If you are thinking I could create some kind of build pipeline on an x86 architecture, well, great idea! But I like the pain and the challenge, so I want to be able to build from my machine and just ship the damn container image!&lt;/p&gt;
&lt;p&gt;Before we deep dive into the Docker code, keep in mind that my project is structured as a monorepo. I have frontend and backend colocated in the same project and my folder structure looks more or less like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/_astro/ec.23yjj.css&quot;&gt;&lt;script type=&quot;module&quot; src=&quot;/_astro/ec.8zarh.js&quot;&gt;&lt;/script&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;├── Dockerfile&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;├── README.md&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;├── backend&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;└── frontend&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;.├── Dockerfile├── README.md├── backend└── frontend&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;So I rolled up my sleeves and came up with this first version of &lt;code&gt;Dockerfile&lt;/code&gt; (of which you get to see a simplified version just to get to the point):&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;dockerfile&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# build container&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; rust:1.68.2-slim-buster &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; backend&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; apt update &amp;#x26;&amp;#x26; apt install -y librust-openssl-dev libssl-dev&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; mkdir /app&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;COPY&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; backend /app/backend&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; cd /app/backend &amp;#x26;&amp;#x26; cargo build --release&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# frontend build container removed for simplicity&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# target container&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; rust:1.68.2-slim-buster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; mkdir /app&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;COPY&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; --from=backend /app/backend/target/release/backend /app/backend&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;WORKDIR&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; /app&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;CMD&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;./backend&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;EXPOSE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; 3000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;ENV&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; RUST_LOG=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;info&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;ENV&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; PORT=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;3000&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;# build containerFROM rust:1.68.2-slim-buster as backendRUN apt update &amp;#x26;&amp;#x26; apt install -y librust-openssl-dev libssl-devRUN mkdir /appCOPY backend /app/backendRUN cd /app/backend &amp;#x26;&amp;#x26; cargo build --release# frontend build container removed for simplicity# target containerFROM rust:1.68.2-slim-busterRUN mkdir /appCOPY --from=backend /app/backend/target/release/backend /app/backendWORKDIR /appCMD [&amp;#x22;./backend&amp;#x22;]EXPOSE 3000ENV RUST_LOG=&amp;#x22;info&amp;#x22;ENV PORT=&amp;#x22;3000&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Let’s break down what’s happening here.&lt;/p&gt;
&lt;p&gt;This is a &lt;a href=&quot;https://docs.docker.com/build/building/multi-stage/&quot;&gt;multi-stage Docker build&lt;/a&gt; which, in short, means that I am using an intermediate container that knows how to compile the Rust binary. Then I can build the target container by copying over the binary from the build container.&lt;/p&gt;
&lt;p&gt;There are a few advantages to this approach:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It’s easier to end up with a smaller target container because it won’t contain all the baggage of the build tools. In fact, the build happens in a dedicated container which is not the one that gets shipped to production.&lt;/li&gt;
&lt;li&gt;If you are building multiple things (in my case a frontend and a backend) you can parallelise these parts by using several specialised build containers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s now review the current &lt;code&gt;Dockerfile&lt;/code&gt; and go through the main bits:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;dockerfile&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# build container&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; rust:1.68.2-slim-buster &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; backend&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; apt update &amp;#x26;&amp;#x26; apt install -y librust-openssl-dev libssl-dev&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; mkdir /app&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;COPY&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; backend /app/backend&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; cd /app/backend &amp;#x26;&amp;#x26; cargo build --release&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;# build containerFROM rust:1.68.2-slim-buster as backendRUN apt update &amp;#x26;&amp;#x26; apt install -y librust-openssl-dev libssl-devRUN mkdir /appCOPY backend /app/backendRUN cd /app/backend &amp;#x26;&amp;#x26; cargo build --release# ...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This is the build container. It’s responsible &lt;em&gt;just&lt;/em&gt; for building the executable binary by compiling the Rust code.&lt;/p&gt;
&lt;p&gt;In short, what’s happening here is the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We start from a Debian-based Rust container which we label &lt;code&gt;backend&lt;/code&gt;. This base image contains all the build tools that we are expected to use to compile Rust-based projects (&lt;code&gt;cargo&lt;/code&gt;, &lt;code&gt;rustc&lt;/code&gt;, etc.).&lt;/li&gt;
&lt;li&gt;Because the project uses some crates that require &lt;code&gt;openssl&lt;/code&gt; (such as &lt;code&gt;sqlx&lt;/code&gt; and &lt;code&gt;reqwest&lt;/code&gt;) we need to make sure &lt;code&gt;openssl&lt;/code&gt; is present in the build environment.&lt;/li&gt;
&lt;li&gt;We create the &lt;code&gt;/app/backend&lt;/code&gt; folder and copy all the Rust source code in there.&lt;/li&gt;
&lt;li&gt;Finally, we run &lt;code&gt;cargo build --release&lt;/code&gt; to compile the executable binary for the app.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s now look at the target container:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;dockerfile&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# target container&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; rust:1.68.2-slim-buster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; mkdir /app&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;COPY&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; --from=backend /app/backend/target/release/backend /app/backend&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;WORKDIR&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; /app&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;CMD&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;./backend&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;EXPOSE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; 3000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;ENV&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; RUST_LOG=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;info&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;ENV&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; PORT=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;3000&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;# ...# target containerFROM rust:1.68.2-slim-busterRUN mkdir /appCOPY --from=backend /app/backend/target/release/backend /app/backendWORKDIR /appCMD [&amp;#x22;./backend&amp;#x22;]EXPOSE 3000ENV RUST_LOG=&amp;#x22;info&amp;#x22;ENV PORT=&amp;#x22;3000&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The first (and probably unexpected bit) is that we are using the same base image as our build container. This is something that I wasn’t really happy with because it means we give away one of the benefits of multi-stage containers: keeping the target container small.&lt;/p&gt;
&lt;p&gt;The reason for this is that I tried other smaller base images, such as plain Debian (slim) or even Alpine and in all these attempts I ended up with different runtime errors indicating some kind of missing library.&lt;/p&gt;
&lt;p&gt;Out of frustration, I eventually capitulated, and decided &lt;em&gt;this is fine&lt;/em&gt; 🐶☕️🔥 and moved on with my life (massive spoiler alert: I’ll eventually get to regret this decision).&lt;/p&gt;
&lt;p&gt;The other bits in this &lt;code&gt;Dockerfile&lt;/code&gt; are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Again, we create an &lt;code&gt;/app&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;We copy from the &lt;code&gt;backend&lt;/code&gt; build container the &lt;code&gt;backend&lt;/code&gt; binary into &lt;code&gt;/app/backend&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We set the working directory of this container to &lt;code&gt;/app&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We define the default runtime command to execute the &lt;code&gt;backend&lt;/code&gt; binary we just copied.&lt;/li&gt;
&lt;li&gt;We expose port &lt;code&gt;3000&lt;/code&gt; and set some environment variables.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Great, all clear?!&lt;/p&gt;
&lt;p&gt;Awesome! Let’s build this, now! 🛠️&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--platform&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;linux/amd64&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;docker build --platform linux/amd64 .&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The secret ingredient here is the &lt;code&gt;--platform&lt;/code&gt; flag. In case you didn’t know, Docker has &lt;a href=&quot;https://docs.docker.com/build/building/multi-platform/&quot;&gt;multi-platform&lt;/a&gt; capabilities!&lt;/p&gt;
&lt;p&gt;This flag uses &lt;code&gt;buildkit&lt;/code&gt;, &lt;code&gt;buildx&lt;/code&gt; and &lt;code&gt;QEMU&lt;/code&gt; behind the scene to build the container for the specified target architecture, regardless what’s your current architecture.&lt;/p&gt;
&lt;p&gt;This is what allows us to build a &lt;code&gt;linux/amd64&lt;/code&gt; binary on a machine with a different architecture such as a Mac silicon (&lt;em&gt;AArch64&lt;/em&gt;).&lt;/p&gt;
&lt;h2 id=&quot;going-to-production-and-container-size-issues&quot;&gt;Going to production and container size issues&lt;/h2&gt;
&lt;p&gt;Long story short, I was eventually happy with this approach and I &lt;em&gt;shipped&lt;/em&gt; the resulting container.&lt;/p&gt;
&lt;p&gt;I didn’t initially pay too much attention to the container size, but I did realise that it took a &lt;em&gt;significantly long time&lt;/em&gt; to transfer it over the wire to the target machine. It is also worth calling out that here we are not using a Docker registry but just shipping raw TAR files for the Docker image.&lt;/p&gt;
&lt;p&gt;Don’t ask me why… didn’t I tell you I don’t have a say in the target environment? 😅&lt;/p&gt;
&lt;p&gt;Ok, so now it’s easy to conclude two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The networking between my development machine and the production machine is not great which is something outside my control, unfortunately.&lt;/li&gt;
&lt;li&gt;The filesize of this container must be &lt;em&gt;significantly big&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I discovered this cool tool called &lt;a href=&quot;https://github.com/wagoodman/dive&quot;&gt;&lt;code&gt;dive&lt;/code&gt;&lt;/a&gt; to inspect container images and I analysed my image.&lt;/p&gt;
&lt;p&gt;A whopping &lt;strong&gt;900 MB**&lt;/strong&gt; is what came out!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;this big gif (Paul McCartney)&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;480&quot; height=&quot;270&quot; src=&quot;https://loige.co/_astro/big.BUoui5SJ_16zpkM.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;That felt indeed like a lot for a container &lt;em&gt;just&lt;/em&gt; running a Rust-based binary!&lt;/p&gt;
&lt;p&gt;Maybe I can try to optimise something to reduce the container image size.&lt;/p&gt;
&lt;p&gt;It cannot be that hard, right? 😇&lt;/p&gt;
&lt;h2 id=&quot;second-attempt-reducing-the-image-file-size&quot;&gt;Second attempt: reducing the image file size&lt;/h2&gt;
&lt;p&gt;My first idea was to just try again with a Linux Alpine base image for the target container. I have used Alpine in the past and it comes with its quirks but it’s always quite reliable when it comes to keeping the container image size small.&lt;/p&gt;
&lt;p&gt;So I just changed:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;dockerfile&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# target container&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; rust:1.68.2-slim-buster&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;# ...# target containerFROM rust:1.68.2-slim-buster# ...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;with:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;dockerfile&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# target container&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; alpine:3.17.3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;# ...# target containerFROM alpine:3.17.3# ...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And built the container, again:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;--platform&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;linux/amd64&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;docker build --platform linux/amd64 .&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;It built just fine, but now when we try to run the resulting container image, this is what we get!&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;Could not open &apos;/lib64/ld-linux-x86-64.so.2&apos;: No such file or directory&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;Could not open &amp;#x27;/lib64/ld-linux-x86-64.so.2&amp;#x27;: No such file or directory&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;I honestly had no idea what that meant, so after some careful googling, this is &lt;a href=&quot;https://www.reddit.com/r/docker/comments/wqxqff/comment/ikq1ol5/?utm_source=reddit&amp;#x26;utm_medium=web2x&amp;#x26;context=3&quot;&gt;what I found&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You problem is you are using an alpine image, and docker assumes glibc. alpine uses musl not glibc. Hence why /lib64/ld-linux-x86-64.so.2 doesn’t exist.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I also discovered this amazing article: &lt;a href=&quot;https://kerkour.com/rust-small-docker-image&quot;&gt;How to create small Docker images for Rust&lt;/a&gt; by Sylvain Kerkour. It contains a lot of useful suggestions on how to get small Docker images for Rust projects. It also confirms that we need to build using &lt;a href=&quot;https://musl.libc.org/&quot;&gt;&lt;code&gt;musl&lt;/code&gt;&lt;/a&gt; and avoid glibc if we want to target Alpine base images! Finally, it also recommends trying to remove all dependencies from &lt;code&gt;libssl&lt;/code&gt; and &lt;code&gt;openssl&lt;/code&gt; and rely on &lt;a href=&quot;https://github.com/rustls/rustls&quot;&gt;&lt;code&gt;rustls&lt;/code&gt;&lt;/a&gt; instead.&lt;/p&gt;
&lt;p&gt;If you never heard about &lt;code&gt;musl&lt;/code&gt; this is the official description:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;musl&lt;/code&gt; is an implementation of the C standard library built on top of the Linux system call API, including interfaces defined in the base language standard, POSIX, and widely agreed-upon extensions. musl is lightweight, fast, simple, free, and strives to be correct in the sense of standards-conformance and safety.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And here’s &lt;code&gt;rustls&lt;/code&gt; one:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Rustls&lt;/code&gt; is a modern TLS library written in Rust. It uses &lt;a href=&quot;https://github.com/briansmith/ring&quot;&gt;&lt;code&gt;ring-3&lt;/code&gt;&lt;/a&gt; for cryptography and &lt;a href=&quot;https://github.com/rustls/webpki&quot;&gt;&lt;code&gt;webpki&lt;/code&gt;&lt;/a&gt; for certificate verification.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Overall, what we want is a way to create a self-contained binary, meaning &lt;strong&gt;all the libraries should be statically linked into the executable&lt;/strong&gt; so we don’t have to assume specific libraries have to exist in the execution environment.&lt;/p&gt;
&lt;p&gt;I like the sound of that, but it requires some code changes, so let’s go through all of them, one by one!&lt;/p&gt;
&lt;h3 id=&quot;switching-to-jemallocator&quot;&gt;Switching to jemallocator&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.rs/jemallocator/latest/jemallocator/&quot;&gt;&lt;code&gt;jemallocator&lt;/code&gt;&lt;/a&gt; is a crate that provides binding to &lt;a href=&quot;https://jemalloc.net/&quot;&gt;&lt;code&gt;Jemalloc&lt;/code&gt;&lt;/a&gt;, a general purpose &lt;code&gt;malloc(3)&lt;/code&gt; implementation.&lt;/p&gt;
&lt;p&gt;This is actually not a mandatory step, but Sylvain’s article mentions that the default &lt;code&gt;musl&lt;/code&gt; allocator is not optimized for speed and that &lt;code&gt;jemalloc&lt;/code&gt; should help us with making sure we don’t lose throughput just by switching to &lt;code&gt;musl&lt;/code&gt;. I haven’t done any benchmark myself, but I trust Sylvain, so let’s do this!&lt;/p&gt;
&lt;p&gt;In order to use the &lt;code&gt;jemallocator&lt;/code&gt; crate, we need 2 code changes, the first one is in our &lt;code&gt;main.rs&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame has-title&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;main.rs&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// Use Jemalloc only for musl-64 bits platforms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;#[cfg(all(target_env &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;musl&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;, target_pointer_width &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;64&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;))]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;#[global_allocator]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#A626A4&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#875D01&quot;&gt;ALLOC&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;jemallocator&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Jemalloc&lt;/span&gt;&lt;span style=&quot;--1:#383A42&quot;&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0&quot;&gt;jemallocator&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#4EC9B0;--1:#016C9A&quot;&gt;Jemalloc&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;// ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;// ...// Use Jemalloc only for musl-64 bits platforms#[cfg(all(target_env = &amp;#x22;musl&amp;#x22;, target_pointer_width = &amp;#x22;64&amp;#x22;))]#[global_allocator]static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;// ...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And, we also need to add the &lt;code&gt;jmallocator&lt;/code&gt; crate to our &lt;code&gt;Cargo.toml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;toml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#3360C1&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#3360C1&quot;&gt;&apos;cfg(all(target_env&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#3360C1&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#3360C1&quot;&gt;&quot;musl&quot;,&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#3360C1&quot;&gt;target_pointer_width&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#3360C1&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#3360C1&quot;&gt;&quot;64&quot;))&apos;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#3360C1&quot;&gt;dependencies&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#3360C1&quot;&gt;jemallocator&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;0.5&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;# ...[target.&amp;#x27;cfg(all(target_env = &amp;#x22;musl&amp;#x22;, target_pointer_width = &amp;#x22;64&amp;#x22;))&amp;#x27;.dependencies.jemallocator]version = &amp;#x22;0.5&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;I haven’t seen this kind of syntax before but my understanding of it is &lt;em&gt;“if compiling for a 64bit architecture with &lt;code&gt;musl&lt;/code&gt; we want &lt;code&gt;jemallocator&lt;/code&gt; version &lt;code&gt;0.5&lt;/code&gt; installed as an additional dependency”&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&quot;switching-to-rustls&quot;&gt;Switching to RusTLS&lt;/h3&gt;
&lt;p&gt;This part is a bit tricky. We need to figure out which ones of our dependencies rely on &lt;code&gt;libssl&lt;/code&gt; as a dynamic library and configure those to use RusTLS instead.&lt;/p&gt;
&lt;p&gt;In my case the two problematic crates are &lt;code&gt;sqlx&lt;/code&gt; (a relational database client) and &lt;code&gt;reqwest&lt;/code&gt; (an http client). Thankfully they both support RusTLS out of the box, you just need to make sure to use the right feature flags.&lt;/p&gt;
&lt;p&gt;This was an extract of my first version of the &lt;code&gt;Cargo.toml&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;toml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#3360C1&quot;&gt;dependencies&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;reqwest&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;0.11.17&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;sqlx&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;0.6.2&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;features&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = [&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;runtime-tokio-native-tls&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;mysql&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;chrono&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;offline&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;# ...[dependencies]# ...reqwest = { version = &amp;#x22;0.11.17&amp;#x22; }sqlx = { version = &amp;#x22;0.6.2&amp;#x22;, features = [&amp;#x22;runtime-tokio-native-tls&amp;#x22;, &amp;#x22;mysql&amp;#x22;, &amp;#x22;chrono&amp;#x22;, &amp;#x22;offline&amp;#x22;] }# ...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And this is how I changed them to use RusTLS instead:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;toml&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#3360C1&quot;&gt;dependencies&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;reqwest&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;0.11.17&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;default-features&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#875D01&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;features&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = [&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;rustls-tls&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;sqlx&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = { &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;0.6.2&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#9CDCFE;--1:#AF4238&quot;&gt;features&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; = [&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;runtime-tokio-rustls&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;mysql&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;chrono&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;offline&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;] }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;# ...[dependencies]# ...reqwest = { version = &amp;#x22;0.11.17&amp;#x22;, default-features = false, features = [&amp;#x22;rustls-tls&amp;#x22;] }sqlx = { version = &amp;#x22;0.6.2&amp;#x22;, features = [&amp;#x22;runtime-tokio-rustls&amp;#x22;, &amp;#x22;mysql&amp;#x22;, &amp;#x22;chrono&amp;#x22;, &amp;#x22;offline&amp;#x22;] }# ...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;For &lt;code&gt;sqlx&lt;/code&gt; we are replacing the &lt;code&gt;runtime-tokio-native-tls&lt;/code&gt; feature with &lt;code&gt;runtime-tokio-rustls&lt;/code&gt;. &lt;code&gt;reqwest&lt;/code&gt; is a bit trickier and it took me a while to figure out that I couldn’t just enable the &lt;code&gt;rustls-tls&lt;/code&gt; feature, but I also needed to specify &lt;code&gt;default-features = false&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;compiling-rust-using-musl&quot;&gt;Compiling Rust using musl&lt;/h3&gt;
&lt;p&gt;Now let’s get to the fun part, compiling our Rust executable, using &lt;code&gt;musl&lt;/code&gt;. Full disclaimer I have little to no idea about what I am doing here, so I am mostly just reporting the steps I copied from Sylvain’s article.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;I have no idea what I am doing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;450&quot; height=&quot;306&quot; src=&quot;https://loige.co/_astro/no-idea.Dt9v-1iG_Ce9lj.webp&quot; &gt;&lt;/p&gt;
&lt;p&gt;Let’s update our &lt;code&gt;Dockerfile&lt;/code&gt;, starting with the &lt;code&gt;backend&lt;/code&gt; stage:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;dockerfile&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; rust:1.68.2-slim-buster &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; backend&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;ENV&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; RUSTFLAGS=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&apos;-C linker=x86_64-linux-gnu-gcc&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;ENV&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; CC_x86_64_unknown_linux_musl=clang&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;ENV&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; AR_x86_64_unknown_linux_musl=llvm-ar&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;ENV&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_RUSTFLAGS=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;-Clink-self-contained=yes -Clinker=rust-lld&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;ENV&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_RUNNER=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;qemu-x86_64 -L /usr/x86-64-linux-gnu&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; rustup target add x86_64-unknown-linux-musl&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; apt update &amp;#x26;&amp;#x26; apt install -y musl-tools musl-dev build-essential gcc-x86-64-linux-gnu clang llvm&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; update-ca-certificates&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; mkdir /app&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;COPY&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; backend /app/backend&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; cd /app/backend &amp;#x26;&amp;#x26; cargo build --target x86_64-unknown-linux-musl --release&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;FROM rust:1.68.2-slim-buster as backendENV RUSTFLAGS=&amp;#x27;-C linker=x86_64-linux-gnu-gcc&amp;#x27;ENV CC_x86_64_unknown_linux_musl=clangENV AR_x86_64_unknown_linux_musl=llvm-arENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_RUSTFLAGS=&amp;#x22;-Clink-self-contained=yes -Clinker=rust-lld&amp;#x22;ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_RUNNER=&amp;#x22;qemu-x86_64 -L /usr/x86-64-linux-gnu&amp;#x22;RUN rustup target add x86_64-unknown-linux-muslRUN apt update &amp;#x26;&amp;#x26; apt install -y musl-tools musl-dev build-essential gcc-x86-64-linux-gnu clang llvmRUN update-ca-certificatesRUN mkdir /appCOPY backend /app/backendRUN cd /app/backend &amp;#x26;&amp;#x26; cargo build --target x86_64-unknown-linux-musl --release&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We added a bunch of environment variables that should make sure that when Rust targets &lt;code&gt;x86_64-unknown-linux-musl&lt;/code&gt; we use &lt;code&gt;qemu&lt;/code&gt; and a bunch of other magic Rust flags that somehow get the job done (don’t ask me how, plz)!&lt;/p&gt;
&lt;p&gt;Then, we use &lt;code&gt;rustup&lt;/code&gt; to install the &lt;code&gt;x86_64-unknown-linux-musl&lt;/code&gt; target.&lt;/p&gt;
&lt;p&gt;We also install a bunch of system-level dependencies that are needed for the build: &lt;code&gt;musl-tools musl-dev build-essential gcc-x86-64-linux-gnu clang llvm&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And finally, we use the &lt;code&gt;--target x86_64-unknown-linux-musl&lt;/code&gt; in our &lt;code&gt;cargo build&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;Awesome! This is now building our executable producing a statically linked binary using musl and RusTLS!&lt;/p&gt;
&lt;p&gt;There’s one tiny extra change we need in our target container. When we use the &lt;code&gt;--target&lt;/code&gt; flag, the resulting file will be saved in a slightly different path, so we need to change this line:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;dockerfile&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;COPY&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; --from=backend /app/backend/target/release/backend /app/backend&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;# ...COPY --from=backend /app/backend/target/release/backend /app/backend# ...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;to this line:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;dockerfile&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;COPY&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; --from=backend /app/backend/target/x86_64-unknown-linux-musl/release/backend /app/backend&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;# ...COPY --from=backend /app/backend/target/x86_64-unknown-linux-musl/release/backend /app/backend# ...&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Note the extra &lt;code&gt;x86_64-unknown-linux-musl&lt;/code&gt; in the new path.&lt;/p&gt;
&lt;p&gt;And that’s it, really!&lt;/p&gt;
&lt;p&gt;Now we can build again with &lt;code&gt;docker build --platform linux/amd64 .&lt;/code&gt; and this time we get a container image size of &lt;strong&gt;100 MB&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;8x size reduction! Not bad! 🎉&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;small ratatouille gif&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;auto&quot; width=&quot;400&quot; height=&quot;180&quot; src=&quot;https://loige.co/_astro/small.BBBMP6nN_ZNmcpP.webp&quot; &gt;&lt;/p&gt;
&lt;h2 id=&quot;version-3-simpler--faster-build-container&quot;&gt;Version 3: simpler &amp;#x26; faster build container&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;UPDATE 2023-05-06&lt;/strong&gt;: Thanks to all the comments I received on &lt;a href=&quot;https://lobste.rs/s/alzpfn/building_x86_rust_containers_from_mac&quot;&gt;a lobste.rs thread&lt;/a&gt; (special thanks to &lt;em&gt;jmillikin&lt;/em&gt; and &lt;em&gt;david_chisnall&lt;/em&gt;) I ended up with a revised version of the build container which is simpler and build a bit faster.&lt;/p&gt;
&lt;p&gt;Here’s the final &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;dockerfile&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; rust:1.68.2-slim-buster &lt;/span&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; backend&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# Dependency `ring-3` requires a cross-compiler for bundled C/C++&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#74A061;--1:#646568;--1fs:italic&quot;&gt;# sources, and may require Perl for some the target platforms.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; apt update &amp;#x26;&amp;#x26; apt install -y --no-install-recommends clang llvm perl&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; update-ca-certificates&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; rustup target add x86_64-unknown-linux-musl&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;COPY&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; backend /app/backend&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;ENV&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; CC_x86_64_unknown_linux_musl=clang&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;ENV&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; RUST_BACKTRACE=full&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;--mount=type=cache,target=/app/backend/target,rw \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;--mount=type=cache,target=/usr/local/cargo/registry,rw \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;cd /app/backend &amp;#x26;&amp;#x26; \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;cargo build --target x86_64-unknown-linux-musl --release &amp;#x26;&amp;#x26; \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span class=&quot;indent&quot;&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;cp /app/backend/target/x86_64-unknown-linux-musl/release/backend /app/backend/server&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; alpine:3.17.3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; mkdir /app&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;COPY&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; --from=backend /app/backend/server /app/backend&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;WORKDIR&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; /app&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;WORKDIR&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; /app&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;CMD&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;./backend&quot;&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;EXPOSE&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; 3000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;ENV&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; RUST_LOG=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;info&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#569CD6;--1:#3360C1&quot;&gt;ENV&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; PORT=&lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&quot;3000&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;FROM rust:1.68.2-slim-buster as backend# Dependency &amp;#x60;ring-3&amp;#x60; requires a cross-compiler for bundled C/C++# sources, and may require Perl for some the target platforms.RUN apt update &amp;#x26;&amp;#x26; apt install -y --no-install-recommends clang llvm perlRUN update-ca-certificatesRUN rustup target add x86_64-unknown-linux-muslCOPY backend /app/backendENV CC_x86_64_unknown_linux_musl=clangENV RUST_BACKTRACE=fullRUN \  --mount=type=cache,target=/app/backend/target,rw \  --mount=type=cache,target=/usr/local/cargo/registry,rw \  cd /app/backend &amp;#x26;&amp;#x26; \  cargo build --target x86_64-unknown-linux-musl --release &amp;#x26;&amp;#x26; \  cp /app/backend/target/x86_64-unknown-linux-musl/release/backend /app/backend/serverFROM alpine:3.17.3RUN mkdir /appCOPY --from=backend /app/backend/server /app/backendWORKDIR /appWORKDIR /appCMD [&amp;#x22;./backend&amp;#x22;]EXPOSE 3000ENV RUST_LOG=&amp;#x22;info&amp;#x22;ENV PORT=&amp;#x22;3000&amp;#x22;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;These changes are removing the need for &lt;code&gt;qemu&lt;/code&gt; and making everything simpler.&lt;/p&gt;
&lt;p&gt;I also learned about Docker cache mounts thanks to &lt;a href=&quot;https://d0nut.hashnode.dev/entering-the-garden-of-ferris&quot;&gt;an article by Nathanial Lattimer&lt;/a&gt; which is something that helps a ton in speeding up subsequent builds. This allows us to keep the built dependencies in the cache and rebuild only the changes made on the app!&lt;/p&gt;
&lt;p&gt;I am much happier with these changes. That’s the power of sharing your stuff even if you don’t feel like an expert on it! So thanks to everyone reading this and suggesting various improvements! Please keep doing that if you see more opportunities for improvement!&lt;/p&gt;
&lt;h2 id=&quot;docker-history&quot;&gt;Docker history&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;UPDATE 2023-05-07&lt;/strong&gt;: I already mentioned &lt;code&gt;dive&lt;/code&gt; as a way to check the layers making up a given Docker image.&lt;/p&gt;
&lt;p&gt;Today I discovered there’s a much simpler way to do that without having to install any third-party tool: &lt;code&gt;docker history&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You just use:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame is-terminal&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;span class=&quot;title&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sr-only&quot;&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#DCDCAA;--1:#3360C1&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;history&lt;/span&gt;&lt;span style=&quot;--0:#D4D4D4;--1:#383A42&quot;&gt; &lt;/span&gt;&lt;span style=&quot;--0:#CE9178;--1:#387138&quot;&gt;&amp;#x3C;image_id&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;docker history &lt;image_id&gt;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And you will get a breakdown of all the commands used to build that image and how much space every one of them is taking.&lt;/p&gt;
&lt;p&gt;In my case, I see something like this:&lt;/p&gt;
&lt;div class=&quot;expressive-code&quot;&gt;&lt;figure class=&quot;frame&quot;&gt;&lt;figcaption class=&quot;header&quot;&gt;&lt;/figcaption&gt;&lt;pre data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;e7c3a275c427   10 minutes ago   ENV MAILCHIMP_LIST_ID=                          0B        buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   ENV MAILCHIMP_API_KEY=                          0B        buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   ENV MAILCHIMP_ENDPOINT=                         0B        buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   ENV GEOIP_PATH=/app/geoip/GeoLite2-City.mmdb    0B        buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   ENV FRONTEND_PATH=/app/frontend                 0B        buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   ENV IMAGES_PATH=/app/images                     0B        buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   ENV SECRET=                                     0B        buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   ENV DATABASE_URL=                               0B        buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   ENV PORT=3000                                   0B        buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   ENV RUST_LOG=info                               0B        buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   ENV VERSION=0.0.29                              0B        buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   EXPOSE map[3000/tcp:{}]                         0B        buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   CMD [&quot;./backend&quot;]                               0B        buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   WORKDIR /app                                    0B        buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   COPY images /app/images # buildkit              3.82MB    buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   COPY geoip/GeoLite2-City.mmdb /app/geoip/Geo…   71.8MB    buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   RUN |1 version=0.0.29 /bin/sh -c mkdir /app/…   0B        buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   COPY /app/frontend/dist /app/frontend # buil…   865kB     buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   COPY /app/backend/server /app/backend # buil…   22.5MB    buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   RUN |1 version=0.0.29 /bin/sh -c mkdir /app …   0B        buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      10 minutes ago   ARG version                                     0B        buildkit.dockerfile.v0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      5 weeks ago      /bin/sh -c #(nop)  CMD [&quot;/bin/sh&quot;]              0B&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;ec-line&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;span style=&quot;--0:#d4d4d4;--1:#383a42&quot;&gt;&amp;#x3C;missing&gt;      5 weeks ago      /bin/sh -c #(nop) ADD file:9a4f77dfaba7fd2aa…   7.05MB&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class=&quot;copy&quot;&gt;&lt;button title=&quot;Copy to clipboard&quot; data-copied=&quot;Copied!&quot; data-code=&quot;IMAGE          CREATED          CREATED BY                                      SIZE      COMMENTe7c3a275c427   10 minutes ago   ENV MAILCHIMP_LIST_ID=                          0B        buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   ENV MAILCHIMP_API_KEY=                          0B        buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   ENV MAILCHIMP_ENDPOINT=                         0B        buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   ENV GEOIP_PATH=/app/geoip/GeoLite2-City.mmdb    0B        buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   ENV FRONTEND_PATH=/app/frontend                 0B        buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   ENV IMAGES_PATH=/app/images                     0B        buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   ENV SECRET=                                     0B        buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   ENV DATABASE_URL=                               0B        buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   ENV PORT=3000                                   0B        buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   ENV RUST_LOG=info                               0B        buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   ENV VERSION=0.0.29                              0B        buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   EXPOSE map[3000/tcp:{}]                         0B        buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   CMD [&amp;#x22;./backend&amp;#x22;]                               0B        buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   WORKDIR /app                                    0B        buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   COPY images /app/images # buildkit              3.82MB    buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   COPY geoip/GeoLite2-City.mmdb /app/geoip/Geo…   71.8MB    buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   RUN |1 version=0.0.29 /bin/sh -c mkdir /app/…   0B        buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   COPY /app/frontend/dist /app/frontend # buil…   865kB     buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   COPY /app/backend/server /app/backend # buil…   22.5MB    buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   RUN |1 version=0.0.29 /bin/sh -c mkdir /app …   0B        buildkit.dockerfile.v0&lt;missing&gt;      10 minutes ago   ARG version                                     0B        buildkit.dockerfile.v0&lt;missing&gt;      5 weeks ago      /bin/sh -c #(nop)  CMD [&amp;#x22;/bin/sh&amp;#x22;]              0B&lt;missing&gt;      5 weeks ago      /bin/sh -c #(nop) ADD file:9a4f77dfaba7fd2aa…   7.05MB&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;/button&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This is telling me that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The base image adds an overhead of about 7MB&lt;/li&gt;
&lt;li&gt;The Rust binary is about 22MB&lt;/li&gt;
&lt;li&gt;Frontend assets and images make up together for about 4MB&lt;/li&gt;
&lt;li&gt;Finally, I have a GeoLite DB that makes the bulk of the image with about 72MB&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If we sum all of these we get to the ~100MB that makes up for the entire image size.&lt;/p&gt;
&lt;p&gt;I could probably squeeze a bit more from the Rust binary by stripping debug symbols or doing other compilation optimizations, but I am honestly quite happy with this result for now!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I hope this article helps you if you are also going through the pain… ehm… the journey of trying to figure out how to cross-compile a Rust binary and run it through a small Docker container.&lt;/p&gt;
&lt;p&gt;This is certainly not the only solution to this problem and I doubt it is the most optimized one (given that I barely know what I am doing here).&lt;/p&gt;
&lt;p&gt;By having some conversations on Twitter someone brought up &lt;a href=&quot;https://github.com/cross-rs/cross&quot;&gt;&lt;code&gt;cross&lt;/code&gt;&lt;/a&gt; which markets itself as &lt;em&gt;“Zero setup cross compilation and cross testing of Rust crates”&lt;/em&gt;, something that sounds very promising.&lt;/p&gt;
&lt;p&gt;I also know that &lt;a href=&quot;https://www.cargo-lambda.info/&quot;&gt;&lt;code&gt;cargo-lambda&lt;/code&gt;&lt;/a&gt; uses the &lt;code&gt;zig&lt;/code&gt; compiler to achieve cross-compilation when packaging lambda functions written in Rust, so it might also be worth exploring how they do that.&lt;/p&gt;
&lt;p&gt;If you know of other solutions, please do let me know in the comment box below!&lt;/p&gt;
&lt;p&gt;Until then, see you in the next article! ❤️&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Original cover photo by &lt;a href=&quot;https://unsplash.com/@noviraj&quot;&gt;novi raj&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/gNhPDsTxz2U&quot;&gt;Unsplash&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;</content:encoded><media:content url="https://loige.co/og/building_x86_rust-containers-from-mac-silicon.png" width="1200" height="630" medium="image" type="image/png"><media:thumbnail url="https://loige.co/og/building_x86_rust-containers-from-mac-silicon.png" width="1200" height="630"/></media:content><category>rust</category><category>docker</category><author>Luciano Mammino</author><comments>https://loige.co/building_x86_rust-containers-from-mac-silicon/#comments</comments><enclosure url="https://loige.co/og/building_x86_rust-containers-from-mac-silicon.png" length="0" type="image/png"/></item></channel></rss>