<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: mkadirtan</title>
    <description>The latest articles on DEV Community by mkadirtan (@mkadirtan).</description>
    <link>https://dev.to/mkadirtan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F508039%2F06371095-180f-4d13-9528-91c9509a996e.png</url>
      <title>DEV Community: mkadirtan</title>
      <link>https://dev.to/mkadirtan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mkadirtan"/>
    <language>en</language>
    <item>
      <title>State of Mind Right Before 2025</title>
      <dc:creator>mkadirtan</dc:creator>
      <pubDate>Tue, 31 Dec 2024 07:22:20 +0000</pubDate>
      <link>https://dev.to/nooptoday/state-of-mind-right-before-2025-3818</link>
      <guid>https://dev.to/nooptoday/state-of-mind-right-before-2025-3818</guid>
      <description>&lt;p&gt;The last two years have been quite an adventure for me. Beware, dear reader, as I reflect on my past two years in both mental and technical aspects and also share my plans for the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mental Aspect
&lt;/h2&gt;

&lt;p&gt;In February 2023, a &lt;a href="https://en.wikipedia.org/wiki/2023_Turkey%E2%80%93Syria_earthquakes" rel="noopener noreferrer"&gt;massive earthquake hit the eastern part of Turkey&lt;/a&gt;. It was a very tragic event. I haven't lost any relatives or friends, but many people did.&lt;/p&gt;

&lt;p&gt;Witnessing the widespread loss and suffering overwhelmed me. Knowing that many of these losses could have been prevented, I was feeling frustrated. Which got amplified by the news and social media.&lt;/p&gt;

&lt;p&gt;I think I experienced what is called &lt;a href="https://mentalhealth.banyantreatmentcenter.com/blog/secondary-trauma-symptoms/#:~:text=What%20Is%20Secondary%20Trauma%3F,traumatic%20experience%20by%20another%20person." rel="noopener noreferrer"&gt;secondary trauma&lt;/a&gt;, and took a serious toll on my mental well-being. The &lt;a href="https://en.wikipedia.org/wiki/2023_Turkish_general_election" rel="noopener noreferrer"&gt;elections were very close - May 2023&lt;/a&gt;, the political climate was very hot, and the work had become very demanding. To relieve, and to distance myself from all these, I took a week off, which didn't help at all.&lt;/p&gt;

&lt;p&gt;I had no room to process all that had been happening and got burned out in the end. I started to look for an exit, any kind of exit.&lt;/p&gt;

&lt;p&gt;Around that time, a minor issue in the workplace was the final straw for me. I quit my job. Without any job offer, or any plan for what to do next. In hindsight, this was a hasty move and a bit immature of me. However it happened, this marks the beginning of my growth journey.&lt;/p&gt;

&lt;p&gt;First, I've looked for jobs abroad. As it is one of the most radical changes a person can have in life, I can leave the country and leave all my tiredness and unhappiness behind me. Let alone getting an offer, I didn't get an interview for two months.&lt;/p&gt;

&lt;p&gt;After two months, I was very short on money and needed a job immediately. Despite hearing negative rumors about the "private fintech company", I accepted their offer thinking 'What can go wrong?'. Needless to say, there wasn't too much public information about this private company.&lt;/p&gt;

&lt;p&gt;After a long time in the same company, working in another one felt refreshing at first. But I wasn't a cultural fit for the company. This time even though I was excited to work in another company, we just couldn't get along. I don't want to take the blame on this one, because the company had a toxic environment where my colleagues told lies behind me, and didn't even accept me socially, even though I tried...&lt;/p&gt;

&lt;p&gt;In February 2024, I got fired out of the blue. Right after that, a colleague called me to say goodbye, he was fired, too. Since I wasn't nearly expecting to get fired, I immediately called my manager and asked if there was a layoff and he didn't tell me. He said, "No, it is just you and one other person. You know due to performance reasons" - which I didn't have and I got pretty good feedback very recently. A couple of weeks later, I saw the news that they laid off a third of the people in the company ( about 100 people ). He just didn't have the heart to tell me...&lt;/p&gt;

&lt;p&gt;I immediately started to look for jobs and also called my previous employee &lt;a href="https://github.com/fustundag" rel="noopener noreferrer"&gt;Fatih Üstündağ&lt;/a&gt;. Though I was quick to quit, we separated in good hearts, and I thought they would accept me back - which they did. For this, I am very grateful.&lt;/p&gt;

&lt;p&gt;Here are the key lessons I've learned from this whole journey:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Focus on what you can control,&lt;/li&gt;
&lt;li&gt;Approach work and life decisions carefully with clear planning,&lt;/li&gt;
&lt;li&gt;Culture fit is very important in the workplace,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Focus on yourself, focus on your goals, get your sleep, eat a healthy diet, and take long walks during the day. Things get a lot easier this way.&lt;/p&gt;

&lt;p&gt;Now, I am at peace and determined more than ever!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Technical Aspect
&lt;/h2&gt;

&lt;p&gt;I've learned a lot during my first year in Getcontact. Then my learning pace slowed, and after a while, I started feeling stuck. I was very comfortable in building Node.js applications. I've learned about databases, performance tricks, etc. The job didn't require much more than that.&lt;/p&gt;

&lt;p&gt;I didn't know what I didn't know. In an attempt to broaden my perspective, I started learning other languages, starting with Rust.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rust: A Promising Start but Not My Type
&lt;/h3&gt;

&lt;p&gt;Rust was all the hype, and I gave it a try. I read the &lt;a href="https://doc.rust-lang.org/book/" rel="noopener noreferrer"&gt;Rust book&lt;/a&gt; and created some small programs. I enjoyed the type system, iterators and borrow checker. But I got lost in macros. To me, a program's code should be as explicit as possible.&lt;/p&gt;

&lt;p&gt;Macro expansions, unusual async workflow along the initially enjoyable type system getting too complex too fast, I decided to move on from Rust. The ideas behind the language were very novel but it didn't grow in me.&lt;/p&gt;

&lt;h3&gt;
  
  
  Go: Breath of Fresh Air
&lt;/h3&gt;

&lt;p&gt;In the past, I had a little experience with Go, and I decided to give it another try. I started with &lt;a href="https://go.dev/tour/" rel="noopener noreferrer"&gt;A Tour of Go&lt;/a&gt;. It is a very lovable language, the simplicity, the ease of use, the package management system... Oh, I feel at home when I write Go. Did I mention the simplicity? It felt like fresh air after JavaScript/Node.js. Luckily, I've had the chance to work with Go in the "private fintech company", and when I came back to Getcontact, I took on the challenge of creating a green field Go project - yay! I am very happy that I am working with Go, and I will probably stick to the language for a long time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Boot.dev
&lt;/h3&gt;

&lt;p&gt;In one of Primeagen's streams, he endorsed &lt;a href="https://www.boot.dev?bannerlord=mkadirtan" rel="noopener noreferrer"&gt;Boot.dev&lt;/a&gt;, an online interactive learning experience for backend engineers. There are a lot of bootcamps and online courses for software engineers, but very few are explicitly designed for backend developers. I enrolled in the program and ate the courses in a big bite. It allowed me to sharpen my data structures and algorithm knowledge, along with Go, Python, and JavaScript, as well as a little bit of C. I recommend this course to software engineers of all experience levels.&lt;/p&gt;

&lt;h3&gt;
  
  
  Master's
&lt;/h3&gt;

&lt;p&gt;I was getting more and more &lt;em&gt;hungry&lt;/em&gt; for software engineering knowledge. So, I enrolled for a master's in Software Engineering at Bogazici University - which I also graduated from in 2019. I had a great experience during those years. However, now that I am 28, my perspective changed. I attended the master's for one semester but some things were not as I expected.&lt;/p&gt;

&lt;p&gt;Though &lt;a href="https://swe.bogazici.edu.tr/en/people" rel="noopener noreferrer"&gt;there are great professors at Bogazici University&lt;/a&gt;, the professors are so busy with other things and the master's program is not their priority. So, I decided to take my master's at a different university. I haven't decided yet, but this time I am especially considering private universities instead of state universities.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Small Visit to Systems Programming: Zig, Tigerbeetle and OSTEP
&lt;/h3&gt;

&lt;p&gt;In another one of Primeagen's streams, I've met with the database that will solve a lot of our problems at Getcontact, Tigerbeetle.&lt;/p&gt;

&lt;p&gt;After reading its documentation, watching Joran Dirk Greef's talks, and going through the papers they used when building the &lt;a href="https://github.com/tigerbeetle/tigerbeetle" rel="noopener noreferrer"&gt;Tigerbeetle&lt;/a&gt;, I was mesmerized. Since I've also quit my master's, I started to learn more about Zig - the language Tigerbeetle is written in. Also, I started to watch out for &lt;a href="https://github.com/andrewrk/" rel="noopener noreferrer"&gt;Andrew Kelley&lt;/a&gt; the inventor of Zig creator of the &lt;a href="https://github.com/andrewrk/groovebasin" rel="noopener noreferrer"&gt;groovebasin&lt;/a&gt;. ( &lt;a href="https://www.youtube.com/watch?v=SCLrNqc9jdE&amp;amp;t=57s" rel="noopener noreferrer"&gt;the joke from here&lt;/a&gt; ), he is a great software engineer and worth following.&lt;/p&gt;

&lt;p&gt;A shout-out to the founder of the Tigerbeetle, &lt;a href="https://github.com/jorangreef" rel="noopener noreferrer"&gt;Joran Dirk Greef&lt;/a&gt;. After realizing the miracles behind the Tigerbeetle, I emailed him about how can I become a better software developer, and he very kindly replied with the greatest resource I've ever read, &lt;a href="https://pages.cs.wisc.edu/~remzi/OSTEP/" rel="noopener noreferrer"&gt;Operating Systems: Three Easy Pieces&lt;/a&gt;, written by Remzi H. Arpaci Dusseau and Andrea C. Arpaci Dusseau. You can search the web for amazing comments about the book, which I won't elaborate on here. Also, I've shared what I've learned from OSTEP in a quick and dirty blog post here: &lt;a href="https://nooptoday.com/ostep-learnings/" rel="noopener noreferrer"&gt;OSTEP Learnings [ Personal ]&lt;/a&gt;, if you want to check it out.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Current Aspect
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I am more busy than when I got burned out&lt;/li&gt;
&lt;li&gt;I am learning a lot more than the last years&lt;/li&gt;
&lt;li&gt;Turkey's economy is in very bad shape&lt;/li&gt;
&lt;li&gt;Politics are still very polarizing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After changing my perspective on life and gaining mechanisms to cope with stress, things got much easier. I am feeling very calm now, despite working harder and living conditions in Turkey are worse compared to previous years. My journey in the last two years &lt;strong&gt;clicked&lt;/strong&gt; something in my head.&lt;/p&gt;

&lt;p&gt;Aside from internal transformation, one smallest change led to the biggest impact in my life. &lt;a href="https://www.reddit.com/r/DecidingToBeBetter/comments/11kv2ln/how_walks_will_change_your_life/" rel="noopener noreferrer"&gt;Taking long walks during the day.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another thing I realized is, it is good to have people you look up to. Primeagen was one of the first people that helped me change my perspective. I know he does some silly things on the stream to enjoy people, but he also shares great life lessons. Well ackshually, his transformation story after the college years helped me gain confidence in what I can achieve.&lt;/p&gt;

&lt;p&gt;Another person who has been very influential on my change is my current manager  &lt;a href="https://github.com/eser" rel="noopener noreferrer"&gt;Eser Özvataf&lt;/a&gt;, but he doesn't even know that. He never gave me life advice or career advice directly - besides as replies to my questions. His calm and systematic approach to challenges shaped how I navigate around challenges, too. This has been said a lot of times before, but actions influence other people much more than words. As the saying goes, monkey sees monkey does.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Future Aspect
&lt;/h2&gt;

&lt;p&gt;I've learned that progress is not linear, and setbacks are often disguised opportunities for self-discovery.&lt;/p&gt;

&lt;p&gt;For the future, I am committed to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting measured goals,&lt;/li&gt;
&lt;li&gt;Pursuing meaningful certifications,&lt;/li&gt;
&lt;li&gt;Continuing my personal exploration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Aside from the certifications, I am also looking forward to enrolling in a master's again. Last year, I promised myself to learn how to skate. This year I will be faithful to myself.&lt;/p&gt;

&lt;p&gt;The coming year holds countless possibilities, and I'm eager to face them with the lessons I've learned, the mentors I admire, and a renewed sense of purpose.&lt;/p&gt;

&lt;p&gt;This is the state of mind right before 2025, I wish you all the best for the next year! 🎉&lt;/p&gt;

</description>
      <category>developer</category>
      <category>mentalhealth</category>
      <category>learning</category>
    </item>
    <item>
      <title>What It Means to be a Good Developer?</title>
      <dc:creator>mkadirtan</dc:creator>
      <pubDate>Mon, 29 Jan 2024 12:58:56 +0000</pubDate>
      <link>https://dev.to/nooptoday/what-it-means-to-be-a-good-developer-13b4</link>
      <guid>https://dev.to/nooptoday/what-it-means-to-be-a-good-developer-13b4</guid>
      <description>&lt;p&gt;Cover Photo by &lt;a href="https://unsplash.com/@neom?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;NEOM / Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A good developer knows how to write performant code&lt;br&gt;
A good developer outputs 10x value&lt;br&gt;
A good developer writes well-tested &amp;amp; documented code&lt;br&gt;
...&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The list goes on, but essentially the essence of such statements comes down to that: A good developer is a productive worker.&lt;/p&gt;

&lt;p&gt;In this post, I want to challenge this perspective and come up with a new definition of what it means to be a developer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does a Developer Has, Other People Don't?
&lt;/h2&gt;

&lt;p&gt;We live in a new age, where ordinary people can build things, not just big factories or corporations. Hacking culture, DIY culture, maker movement whatever you name it, all those arose from a single fact: We can build things, too.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The maker movement is *&lt;em&gt;a cultural revolution that places more value on individuals becoming creators of products or services than merely consuming them - *&lt;/em&gt;&lt;a href="https://www.sogolytics.com/blog/maker-movement-industrial-revolution-4-0"&gt;Sogolytics&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Developers has access to build tools, much more than any other industry. In fact, you can argue that developers are the build tools. I believe that is the power we hold.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Should We Do With This Power?
&lt;/h2&gt;

&lt;p&gt;We should strive to create an open and accessible internet to make sure this power stays in the hands of developers. This is what happened so far, but the reason I am writing this article is to make sure we don't forget what we have.&lt;/p&gt;

&lt;p&gt;Everyone wants to change the world, in their own way. We as developers, has the power to make that change happen, in our own ways. Don't wait for someone else to make that change, Do It Yourself. Others will follow, the world is a huge place with so many people living on it. Whatever you want, there are other people that want the same thing. So, go make that change, pioneer new things, change the world just a little bit.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, What Is a Good Developer
&lt;/h2&gt;

&lt;p&gt;Someone who uses their power, to achieve their personal goals using programming. Who solves their own problems first, who builds their own needs first is a good developer.&lt;/p&gt;

&lt;p&gt;Just because there is demand for your skills you learnt throughout the journey, doesn't mean you should aim to improve those skills. Those were not your first concern, when you started out.&lt;/p&gt;

&lt;p&gt;Be yourself, don't let the business shape you into something else. You are the pioneer, they are the newcomer. You shape the culture, you hold the power, you drive the locomotive, businesses try to catch the train.&lt;/p&gt;

&lt;p&gt;So, why should you let some job requirements define what a good developer is?&lt;/p&gt;

&lt;p&gt;Be a good developer, and keep developing. Develop new things, develop existing things from scratch, try out new ideas, challenge the system. The world needs you, as you are.&lt;/p&gt;

</description>
      <category>developer</category>
      <category>internet</category>
      <category>programming</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Introducing feed-rs: Fastest Feed Parser Built With Rust &amp; NAPI-RS</title>
      <dc:creator>mkadirtan</dc:creator>
      <pubDate>Tue, 28 Nov 2023 06:47:26 +0000</pubDate>
      <link>https://dev.to/mkadirtan/introducing-feed-rs-fastest-feed-parser-built-with-rust-napi-rs-21k0</link>
      <guid>https://dev.to/mkadirtan/introducing-feed-rs-fastest-feed-parser-built-with-rust-napi-rs-21k0</guid>
      <description>&lt;p&gt;We all know that Rust is faster than Node.js. But, Node.js performs well for most common operations, such as file reading, database queries, or handling HTTP requests.&lt;/p&gt;

&lt;p&gt;Do you know where Node.js sucks and a language like Rust shines? CPU-bound tasks, such as parsing or serializing data, expensive mathematical operations such as encryption or decryption, etc.&lt;/p&gt;

&lt;p&gt;I needed a feed parser for my project. It had to be compliant with the spec, however, there are various types of feeds, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON feeds,&lt;/li&gt;
&lt;li&gt;Atom feeds,&lt;/li&gt;
&lt;li&gt;RSS with multiple versions ( RSS0, RSS1, RSS2 )
So, I would much rather parse all of them into a common format than deal with each of their intricacies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I couldn't find a package in the NPM, that took down the long road and handled these feeds altogether in a single format. Instead, I tried to build one on my own. In my experience, dealing with XML data in Node.js has always been somewhat painful. After realizing that the rabbit hole might go a little deeper than I expected, I started to look for alternative solutions.&lt;/p&gt;

&lt;p&gt;Then, I remembered that NAPI exists and I can borrow some code from Rust crates into an NPM package!&lt;/p&gt;

&lt;p&gt;Long story short, I've found a beautifully written feed parser in cargo, sprinkled some NAPI sauce onto it, and voila: The fastest Feed Parser in NPM was born.&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://www.npmjs.com/package/@nooptoday/feed-rs" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--58xlbJJX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://static-production.npmjs.com/338e4905a2684ca96e08c7780fc68412.png" height="420" class="m-0" width="800"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://www.npmjs.com/package/@nooptoday/feed-rs" rel="noopener noreferrer" class="c-link"&gt;
          @nooptoday/feed-rs - npm
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;p class="truncate-at-3"&gt;
          Fastest RSS parser with the power of Rust. This package includes Node.js bindings from feed_rs package. Latest version: 0.2.1, last published: 9 days ago. Start using @nooptoday/feed-rs in your project by running `npm i @nooptoday/feed-rs`. There are no other projects in the npm registry using @nooptoday/feed-rs.
        &lt;/p&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://res.cloudinary.com/practicaldev/image/fetch/s--lHsc1BmO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://static-production.npmjs.com/b0f1a8318363185cc2ea6a40ac23eeb2.png" width="32" height="32"&gt;
        npmjs.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;If you are curious about how do you glue the code between Rust and Node.js, here is a very short sneak peek:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[napi]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feed_string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;feed_source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;models&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Feed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse_with_uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;feed_string&lt;/span&gt;&lt;span class="nf"&gt;.as_bytes&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;feed_source&lt;/span&gt;&lt;span class="nf"&gt;.as_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="nf"&gt;.as_str&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;models&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Feed&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_reason&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;())),&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I recommend everyone who deals with CPU-bound tasks on Node.js, to use the NAPI bindings, it is awesome! As a quick guide, you can read more about &lt;a href="https://nooptoday.com/what-did-i-learn-while-creating-feed-rs/"&gt;how to use NAPI-RS to build Node.js packages using Rust.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Benchmarks?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feed-rs          2367 ops/s, ±0.39%   | fastest
fast-xml-parser  1198 ops/s, ±0.26%   | 49.39% slower
rss-parser:      125 ops/s,  ±2.27%   | slowest, 94.72% slower
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, feed-rs is doing double the amount of work than a highly optimized parsing package.&lt;/p&gt;

</description>
      <category>napi</category>
      <category>rust</category>
      <category>node</category>
      <category>performance</category>
    </item>
    <item>
      <title>What Would Marco Polo Think About the WebSockets?</title>
      <dc:creator>mkadirtan</dc:creator>
      <pubDate>Sat, 19 Aug 2023 12:15:35 +0000</pubDate>
      <link>https://dev.to/nooptoday/what-would-marco-polo-think-about-the-websockets-9i1</link>
      <guid>https://dev.to/nooptoday/what-would-marco-polo-think-about-the-websockets-9i1</guid>
      <description>&lt;p&gt;Marco Polo and WebSockets? You might be surprised to hear about their relationship.&lt;/p&gt;

&lt;p&gt;On his visit to Asia, Marco Polo was impressed by the Yam, a postal system built by the Mongol Empire.&lt;/p&gt;

&lt;p&gt;Still no connection? Okay, let's rewind a bit.&lt;/p&gt;




&lt;p&gt;In this fast-paced world, we want everything to happen in real time.&lt;/p&gt;

&lt;p&gt;We want real-time communication, real-time updates on exchanges, real-time money transfers, real-time teleportation, real-time this, and real-time that!&lt;/p&gt;

&lt;p&gt;In the old times, real-time communication wasn't possible. Moreover, communicating over long distances was a lengthy process.&lt;/p&gt;

&lt;p&gt;But it was crucial for the Khans of the Mongol Empire, as it was a geographically large empire. So, they built one of the best postal systems at the time, called the &lt;a href="https://en.wikipedia.org/wiki/Yam_(route)"&gt;Yam&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In my research of the Yam, I couldn't help but notice how similar it is to the Internet we use today.&lt;/p&gt;

&lt;p&gt;In this post, I want to provide a different perspective. A perspective that shines a light on the evolution of real-time technologies of today. Have a great read!&lt;/p&gt;

&lt;h2&gt;
  
  
  Letters
&lt;/h2&gt;

&lt;p&gt;One of the oldest and most complete ways of communication is sending letters. Previous methods of communication lacked some essential features. So what did the letters provide? Why they were so powerful and popular throughout history?&lt;/p&gt;

&lt;p&gt;If you remember from school, there are five fundamental elements to communication:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The source ( sender )&lt;/li&gt;
&lt;li&gt;The message&lt;/li&gt;
&lt;li&gt;The channel&lt;/li&gt;
&lt;li&gt;The target ( receiver )&lt;/li&gt;
&lt;li&gt;Feedback ( Essential for two-ways communication )&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, if I send a letter to my brother:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I am the source,&lt;/li&gt;
&lt;li&gt;the message is the text in the letter,&lt;/li&gt;
&lt;li&gt;the letter is the channel,&lt;/li&gt;
&lt;li&gt;my brother is the target.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is strange that even though we use very different technologies to communicate, the fundamentals are the same. We can find WebSocket equivalents of all the things above. In fact, we can find TCP, HTTP, SMTP, or any other protocol equivalent to these. But let's keep it in the WebSockets.&lt;/p&gt;

&lt;p&gt;WebSocket protocol is built on top of TCP. In other words, the clients must establish a TCP connection to the server first. Then, they can switch to the WebSocket protocol via an upgrade mechanism.&lt;/p&gt;

&lt;p&gt;So, a WebSocket equivalent to the above example would be as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sender IP and Sender Port is the source,&lt;/li&gt;
&lt;li&gt;Bytes of data in the TCP packet are the message,&lt;/li&gt;
&lt;li&gt;Internet / Web is the channel,&lt;/li&gt;
&lt;li&gt;The receiver IP and the Receiver Port is the target.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What about the feedback? Well, if he doesn't write me back there is no feedback and the communication is one-sided. Therefore, a letter contains the address of the receiver as well as the address of the sender, so the receiver can reply.&lt;/p&gt;

&lt;p&gt;In WebSockets, there is no concept of feedback. Even though the underlying TCP connection ensures message delivery via ACK packets, the WebSocket protocol doesn't have such a concept. For that reason, some other protocols exist, such as Socket.IO, Stomp, and more. Those protocols offer a mechanism to ACKnowledge ( Feedback ) that the receiver received the message.&lt;/p&gt;

&lt;p&gt;Apart from fundamental elements, there are other very important aspects to communication.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proving the Authenticity of A Letter
&lt;/h2&gt;

&lt;p&gt;The receiver wants to ensure the message is authentic. Is it coming from the source? There were several mechanisms to ensure the authenticity of a letter.&lt;/p&gt;

&lt;p&gt;To start with, people used stamps and their signatures to prove the letter is written by them. Assuming the receiver knows who uses which stamp and how their signatures look, they can verify the letter is indeed authentic.&lt;/p&gt;

&lt;p&gt;This immediately reminds me of today's Internet. Browsers check the authenticity of the websites by looking at their signatures. In other words, SSL certificates. For example, you can check that you are at &lt;a href="https://nooptoday.com"&gt;https://nooptoday.com&lt;/a&gt; and verify that this is indeed from the correct source!&lt;/p&gt;

&lt;p&gt;Secondly, people could recognize the handwriting of the sender. They could recognize the writing style of the sender. Humans are actually very capable of recognizing patterns. During the days of World War 2, &lt;a href="https://axbom.com/keystroke-dynamics"&gt;telegraph operators were able to distinguish senders by their tapping rhythm and style.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is somewhat persistent throughout all communication methods. For example, if you are a long-time Noop Today reader, you might realize my recent post about RSS feeds was not written by me. It was written by AI. But, if you are a newcomer, you might not realize it.&lt;/p&gt;

&lt;p&gt;People also sent encrypted messages to each other. This further helps prove the authenticity of the sender, assuming only the sender knows how to encrypt the message.&lt;/p&gt;

&lt;p&gt;This is again accomplished by using SSL certificates on the websites. Most web protocols also have their secure counterparts: HTTP &amp;amp; HTTPS, WS &amp;amp; WSS, or SMTP &amp;amp; SMTPS.&lt;/p&gt;

&lt;p&gt;These methods were not great but they worked to some extent. Of course, as you may have noticed, all these methods require a pre-established trust between the parties.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Even today, the Internet contains many security flaws. At least, they are fixed as soon as they are detected. Still, it doesn't mean every web service on the Internet complies with the latest bestest security practices.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
   More About Letters
&lt;/h3&gt;

&lt;p&gt;The letter is a physical channel for communication. This allowed senders to add fragrance to their letters, use quality papers to reflect the importance of their message, or decorate the paper in beautiful ways to convey more than words in their message.&lt;/p&gt;

&lt;p&gt;However, it also means that letters can be lost during transmission, they can be stolen or damaged along the way. This brings us to another important aspect of communication: Reliability.&lt;/p&gt;

&lt;h3&gt;
  
  
   Delivering Messages in A Reliable Way
&lt;/h3&gt;

&lt;p&gt;Well, you've prepared a beautiful letter, sprayed it with a nice perfume, and used the best quality paper for it. You hit send, ehm. excuse me, you gave your letter to a messenger, and you are not sure whether it will reach the receiver.&lt;/p&gt;

&lt;p&gt;What if your message is really important?&lt;/p&gt;

&lt;p&gt;Then you could give your message to a very reputable courier. Which is very similar to using a more trusted service for sending messages from our phones.&lt;/p&gt;

&lt;p&gt;If you don't hear back from the receiver, you can send it again. This method is used by the TCP protocol. The receiver might receive more than one message, but since you send the letter again and again, it will be delivered at least once. This is the algorithm behind &lt;a href="https://www.rabbitmq.com/reliability.html#confirms"&gt;at least once delivery&lt;/a&gt; guarantee provided by message broker softwares such as RabbitMQ, Kafka or Redis.&lt;/p&gt;

&lt;p&gt;People used &lt;a href="https://www.quora.com/How-were-letters-sent-and-delivered-during-the-Renaissance"&gt;very different methods to send their letters&lt;/a&gt; until generally available postal offices were built.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Need for Speed in Information Exchange
&lt;/h2&gt;

&lt;p&gt;The importance of the communication speed is undisputable. But how important it was? I think we can judge its importance for the Mongol Empire, just by looking at how much resources and effort was put into building the Yam.&lt;/p&gt;

&lt;p&gt;It consisted of numerous postal stations ( 1400 in China alone ), countless horses ( up to 50,000 ), and a large number of oxen, mules, carts, boats, dogs, and sheep.&lt;/p&gt;

&lt;p&gt;The goal was to speed up the information exchange within the country. The Mongol Empire was geographically large, and it was crucial to deliver information in a short time from one end of the country to the other.&lt;/p&gt;

&lt;p&gt;China had a similar system before the Yam, but the Mongols took it too far to build a complete information network.&lt;/p&gt;

&lt;h3&gt;
  
  
  How did The Yam Postal System Worked?
&lt;/h3&gt;

&lt;p&gt;The Yam, focused heavily on speed. The postal stations acted as relays. Every postal station contained some amount of horses, and messengers ready to go in demand. Moreover, postal stations are located about 20-40 miles from each other.&lt;/p&gt;

&lt;p&gt;When a message is sent from a postal station, the messenger immediately starts riding to the nearest postal station along the route.&lt;/p&gt;

&lt;p&gt;The initial messenger delivers the letter to the next postal station. Another messenger from the station immediately starts riding to the next station and so on until the letter is reached to the final destination.&lt;/p&gt;

&lt;p&gt;This process is called relaying. The message is relayed through intermediate postal stations.&lt;/p&gt;

&lt;p&gt;Now, I want you to make an experiment. Open your terminal and enter the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# On Macos and Linux&lt;/span&gt;
traceroute nooptoday.com

&lt;span class="c"&gt;# On Windows:&lt;/span&gt;
tracert nooptoday.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait a moment until the command completes, and you will see a similar output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;traceroute: Warning: nooptoday.com has multiple addresses&lt;span class="p"&gt;;&lt;/span&gt; using 188.114.97.3
traceroute to nooptoday.com &lt;span class="o"&gt;(&lt;/span&gt;188.114.97.3&lt;span class="o"&gt;)&lt;/span&gt;, 64 hops max, 52 byte packets
 1  192.168.1.1 &lt;span class="o"&gt;(&lt;/span&gt;192.168.1.1&lt;span class="o"&gt;)&lt;/span&gt;  2.569 ms  2.190 ms  2.045 ms
 2  &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;
 3  172.19.6.129 &lt;span class="o"&gt;(&lt;/span&gt;172.19.6.129&lt;span class="o"&gt;)&lt;/span&gt;  31.203 ms  37.910 ms  29.936 ms
 4  172.16.193.125 &lt;span class="o"&gt;(&lt;/span&gt;172.16.193.125&lt;span class="o"&gt;)&lt;/span&gt;  39.917 ms  42.795 ms  35.853 ms
 5  172.16.60.86 &lt;span class="o"&gt;(&lt;/span&gt;172.16.60.86&lt;span class="o"&gt;)&lt;/span&gt;  24.988 ms
    172.16.60.134 &lt;span class="o"&gt;(&lt;/span&gt;172.16.60.134&lt;span class="o"&gt;)&lt;/span&gt;  33.023 ms  39.132 ms
 6  172.16.60.101 &lt;span class="o"&gt;(&lt;/span&gt;172.16.60.101&lt;span class="o"&gt;)&lt;/span&gt;  31.876 ms
    172.16.60.149 &lt;span class="o"&gt;(&lt;/span&gt;172.16.60.149&lt;span class="o"&gt;)&lt;/span&gt;  40.284 ms  42.080 ms
 7  172.16.198.3 &lt;span class="o"&gt;(&lt;/span&gt;172.16.198.3&lt;span class="o"&gt;)&lt;/span&gt;  36.744 ms
    172.16.198.7 &lt;span class="o"&gt;(&lt;/span&gt;172.16.198.7&lt;span class="o"&gt;)&lt;/span&gt;  58.546 ms
    172.16.198.3 &lt;span class="o"&gt;(&lt;/span&gt;172.16.198.3&lt;span class="o"&gt;)&lt;/span&gt;  51.061 ms
 8  10.40.168.240 &lt;span class="o"&gt;(&lt;/span&gt;10.40.168.240&lt;span class="o"&gt;)&lt;/span&gt;  31.211 ms
    10.40.141.65 &lt;span class="o"&gt;(&lt;/span&gt;10.40.141.65&lt;span class="o"&gt;)&lt;/span&gt;  45.503 ms
    10.40.169.122 &lt;span class="o"&gt;(&lt;/span&gt;10.40.169.122&lt;span class="o"&gt;)&lt;/span&gt;  60.582 ms
 9  ae6.bucarest1.buc.seabone.net &lt;span class="o"&gt;(&lt;/span&gt;93.186.132.6&lt;span class="o"&gt;)&lt;/span&gt;  89.756 ms  77.439 ms  87.002 ms
10  cloudflare.bucarest1.buc.seabone.net &lt;span class="o"&gt;(&lt;/span&gt;93.186.132.11&lt;span class="o"&gt;)&lt;/span&gt;  80.037 ms  107.892 ms  76.112 ms
11  188.114.97.3 &lt;span class="o"&gt;(&lt;/span&gt;188.114.97.3&lt;span class="o"&gt;)&lt;/span&gt;  80.520 ms  76.317 ms  86.985 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Traceroute allows you to see exactly which hops your network packets go through until reaching to the destination server. The hops are the servers between you and the destination, a.k.a relays. Depending on your geographical location the results will be different for you.&lt;/p&gt;

&lt;p&gt;I am using Cloudflare to secure my server, so termination address should belong to the cloudflare as in my example.&lt;/p&gt;

&lt;p&gt;What? Are you not impressed? Okay, how about some visuals? This is the visualization of my connection from Turkey, to the twitter.com. You can try and see the results for yourselves at &lt;a href="https://stefansundin.github.io/traceroute-mapper/"&gt;https://stefansundin.github.io/traceroute-mapper/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DtP8GveX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4x4nadjeux9vwyto9qdt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DtP8GveX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4x4nadjeux9vwyto9qdt.png" alt="Image description" width="800" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Okay, so relaying is pretty much the same compared to the Yam.&lt;/p&gt;

&lt;p&gt;A minor difference is that, messengers in the Yam system cared about the geographical distance and the actual geographical route to their destination, and decided which station they should go next.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.cloudflare.com/learning/network-layer/internet-protocol/"&gt;network packets are routed according to the IP protocol&lt;/a&gt;, and it works a little different. Whatever the case is, the main purpose of the IP protocol is to deliver the packages to the destination and do it efficiently.&lt;/p&gt;

&lt;p&gt;The Yam was optimized to prevent any delays during the transmissions. They contained a lot of horses and riders to send out many messages without waiting for the riders to arrive.&lt;/p&gt;

&lt;p&gt;A similar pattern in the internet protocol is the concept of Ports. You can connect to and from a computer using various ports, up to 65535 in most machines. When you open up countless chrome tabs on your computer, you are connected to each server through a randomly assigned local port of your machine. Again, don't trust me, lets have an experiment.&lt;/p&gt;

&lt;p&gt;Open up the terminal, and enter the following:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You will see a table containing Local Address and the Foreign Address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Proto Recv-Q Send-Q  Local Address          Foreign Address        &lt;span class="o"&gt;(&lt;/span&gt;state&lt;span class="o"&gt;)&lt;/span&gt;
tcp4       0      0  192.168.1.110.51074    104.17.50.74.https     ESTABLISHED
tcp4       0      0  192.168.1.110.51073    ec2-50-17-76-205.https ESTABLISHED
tcp4       0      0  192.168.1.110.51072    server-3-160-246.https ESTABLISHED
tcp4       0      0  192.168.1.110.51071    server-3-160-246.https ESTABLISHED
tcp4       0      0  192.168.1.110.51070    server-3-160-246.https ESTABLISHED
tcp4       0      0  192.168.1.110.51069    ec2-54-88-211-15.https ESTABLISHED
tcp4       0      0  192.168.1.110.51068    ec2-54-88-211-15.https ESTABLISHED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that foreign addresses are usually denoted with https, which means it uses the port 443, while the local addresses contain some random numbers around 50000 range.&lt;/p&gt;

&lt;h3&gt;
  
  
   Marco Polo's Thoughts About The WebSockets and The Yam
&lt;/h3&gt;

&lt;p&gt;Finally, I've received a letter from my dear friend ChatGPT, ehm. sorry, Marco Polo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;My Dearest Friend Noop Today,&lt;/p&gt;

&lt;p&gt;I trust this missive finds you in good health and high spirits. As I recount my awe-inspiring journey through the lands of the Mongol Empire, I am compelled to share a revelation that has captured my imagination in a most profound manner. It appears that the remarkable postal system devised by the illustrious Khans, known as the "Yam," bears striking resemblances not only to the intricate network of computers that weave the tapestry of our modern world, the Internet, but also to a technological marvel of our own time - the WebSocket protocol.&lt;/p&gt;

&lt;p&gt;Imagine, if you will, the vast expanse of the Mongol Empire stretching like an endless steppe. As I traversed these lands, I marveled at the brilliance of the Yam, which connected distant corners of the empire like the sinews of a mighty horse. Dispatch riders, skilled and swift, carried messages along these well-organized routes, spanning empires and cultures. In many ways, these couriers resembled the packets of data that traverse the digital highways of our time.&lt;/p&gt;

&lt;p&gt;But now, let us turn our gaze toward the remarkable WebSocket protocol that graces our modern age. Just as the Yam facilitated the exchange of information across great distances, so does the WebSocket protocol allow for a continuous, bidirectional flow of data between a client and a server. Like the stations of the Yam, our digital servers and data centers act as the lodges for information, housing and transmitting it seamlessly, creating a virtual channel akin to the way the Yam relay stations operated.&lt;/p&gt;

&lt;p&gt;Moreover, the Yam and the WebSocket protocol both share the essence of real-time communication. The Yam ensured that news and orders reached their destinations promptly, just as the WebSocket protocol empowers web applications to communicate instantaneously, enriching user experiences and enabling interactive applications that mirror the swift delivery of messages along the Yam's pathways.&lt;/p&gt;

&lt;p&gt;Additionally, both the Yam and the WebSocket protocol necessitate a certain level of centralization to function efficiently. Just as the Khans maintained control over the Yam, ensuring its proper functioning, the WebSocket protocol relies on servers to manage the connections and facilitate the data exchange, bringing a touch of governance to the flowing information streams.&lt;/p&gt;

&lt;p&gt;The most captivating similarity, however, lies in the way these systems foster interconnectedness. The Yam linked cities and cultures, facilitating cultural exchange and commerce. Similarly, the WebSocket protocol has ushered in an era of dynamic web applications that enable real-time collaboration and engagement, connecting people across the digital landscape much like the Yam connected settlements across the vast Mongol expanse.&lt;/p&gt;

&lt;p&gt;As I reflect upon these similarities, I am struck by the timelessness of human innovation. While the tools and technologies have evolved, the underlying desire to bridge distances, unite people, and share knowledge endures. The echoes of the Yam can be heard in the electronic pulses of the Internet and the WebSocket protocol, reminding us that human ingenuity, whether in the form of hoofbeats, digital signals, or continuous data streams, knows no bounds.&lt;/p&gt;

&lt;p&gt;In closing, my friend, I implore you to contemplate the grand tapestry of history and technology that connects us all. From the desolate expanses of the Mongol Empire to the bustling networks of the Internet and the seamless interactivity of the WebSocket protocol, we are bound by a thread of innovation that stretches across time and space. May we continue to nurture this spirit of connection and progress for generations to come.&lt;/p&gt;

&lt;p&gt;Yours in wonderment, Marco Polo&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is both scary and exciting to hear Marco Polo's thoughts about the real-time technologies of today. What excites me a lot is that he keeps mentioning human progress and our desire to interconnect with each other.&lt;/p&gt;

&lt;p&gt;I believe we've achieved a lot since those days. It is amazing how we are all connected to each other through the internet, well.. except for North Korea of course.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;I think understanding the basic concepts behind the technologies we use today is important. As a civilization, we've achieved great advancements in technology.&lt;/p&gt;

&lt;p&gt;However, humans' basic needs and desires are still pretty much the same. In the old times, people did their best with what they had, but they didn't have today's technological tools.&lt;/p&gt;

&lt;p&gt;I've found it helps me to wrap my head around the various technologies of today if I know how they evolved throughout time, which needs they fulfilled, and how they were implemented before the internet era.&lt;/p&gt;

&lt;p&gt;I hope you learned something new from this post, if you like my content please subscribe to the newsletter or leave a comment below.&lt;/p&gt;

</description>
      <category>websockets</category>
      <category>tcp</category>
      <category>network</category>
      <category>internet</category>
    </item>
    <item>
      <title>Lecture Notes: NLP with Deep Learning - 1</title>
      <dc:creator>mkadirtan</dc:creator>
      <pubDate>Sat, 01 Apr 2023 20:37:43 +0000</pubDate>
      <link>https://dev.to/nooptoday/lecture-notes-nlp-with-deep-learning-1-2j13</link>
      <guid>https://dev.to/nooptoday/lecture-notes-nlp-with-deep-learning-1-2j13</guid>
      <description>&lt;p&gt;I can't believe it has been four years since I finished college. To my surprise, I missed taking courses just for the sake of science.&lt;/p&gt;

&lt;p&gt;Working at a company, putting your knowledge and effort to build something is excellent and satisfying. You also gain experience by doing that.&lt;/p&gt;

&lt;p&gt;But curiosity is a strong human motive to learn something new. I think the latest advances in AI and the hype around ChatGPT and language models triggered my curiosity.&lt;/p&gt;

&lt;p&gt;So, I decided to take open lectures by Standford University on YouTube. I wanted to keep track of my learning progress and share my lecture notes in this series. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🙌🏻 Subscribe to &lt;a href="https://nooptoday.com/"&gt;Noop Today&lt;/a&gt; to join my journey or if you just want to follow along and learn something new.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Meaning of a Word
&lt;/h2&gt;

&lt;p&gt;Even though I used ChatGPT before, I didn't know the science behind it. It all looked like magic to me, as it does to most people.&lt;/p&gt;

&lt;p&gt;In the first lecture, I got really excited to see how we can translate words into a machine-understandable format. The lesson started with the following comic:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ar-QzoQW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nooptoday.com/content/images/2023/04/care-less-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ar-QzoQW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nooptoday.com/content/images/2023/04/care-less-1.png" alt="natural language processing comic - part 1" width="448" height="243"&gt;&lt;/a&gt;Source: &lt;a href="https://languagelog.ldc.upenn.edu/nll/?p=21170"&gt;https://languagelog.ldc.upenn.edu/nll/?p=21170&lt;/a&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Tyr3R4_u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nooptoday.com/content/images/2023/04/care-less-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Tyr3R4_u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nooptoday.com/content/images/2023/04/care-less-2.png" alt="natural language processing comic - part 2" width="753" height="571"&gt;&lt;/a&gt;Source: &lt;a href="https://languagelog.ldc.upenn.edu/nll/?p=21170"&gt;https://languagelog.ldc.upenn.edu/nll/?p=21170&lt;/a&gt;&lt;br&gt;
The comic is a mind-opener that makes you question how you give meanings to words.&lt;/p&gt;

&lt;p&gt;Language constantly evolves, there are new words entering our lives and some words stop being used and some words gain new meanings!&lt;/p&gt;

&lt;p&gt;Moreover, the meaning of a word also changes depending on the &lt;strong&gt;context&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Word Embedding
&lt;/h2&gt;

&lt;p&gt;Word embedding is a large dimensional ( hundreds of dimensions ) space made up of word vectors. A word vector is the mathematical representation of the meaning of a word. &lt;/p&gt;

&lt;p&gt;I'll explain how scientists turn words into mathematics in a minute. But first, let's look at an extremely simplified two-dimensional representation of a word embedding:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IM1s7zLx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nooptoday.com/content/images/2023/04/Screenshot-2023-04-01-at-21.17.49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IM1s7zLx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://nooptoday.com/content/images/2023/04/Screenshot-2023-04-01-at-21.17.49.png" alt="" width="748" height="728"&gt;&lt;/a&gt;Simplified Word Embedding&lt;br&gt;
Of course, there are no labels such as age or gender in a real word embedding, because dimensions don't have to represent a specific thing.&lt;/p&gt;

&lt;p&gt;The meaning of words is too broad to represent in a two-dimensional space. But having too many dimensions make the computation harder. A relatively sufficient word embedding can have 300 dimensions.&lt;/p&gt;

&lt;p&gt;Even though we can't visualize a space with hundreds of dimensions in our heads, it is enough to understand why we need to have so many dimensions for representing words as vectors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Word2Vec Algorithm
&lt;/h2&gt;

&lt;p&gt;Word2Vec is one of the models you can use to translate words into a machine-readable format. Basically, it converts words into vectors.&lt;/p&gt;

&lt;p&gt;I will try to explain how Word2Vec converts words into vectors, but honestly, the idea is all I can present to you. Because I didn't understand the mathematics behind it.&lt;/p&gt;

&lt;p&gt;What do we want to achieve by converting a word to a vector? We want to create a word embedding in which semantically similar words are closer to each other.&lt;/p&gt;

&lt;p&gt;The algorithm is based on the famous quote:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;You shall know a word by the company it keeps.&lt;/em&gt; -&lt;a href="https://en.wikipedia.org/wiki/John_Rupert_Firth"&gt;John Rupert Firth&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Word2Vec algorithm takes a large corpus ( body ) of text as input. Then tries to assign vectors to every unique word in the text. The value of the vector is adjusted iteratively to create a probability function P.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;P(c|o) = Probability of word **o** appear in the context of center word **c**&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The probability function gives the probability of a word appearing in the context of another word. In each iteration, the vectors are adjusted and the probability function gives more accurate results.&lt;/p&gt;

&lt;p&gt;The context words and the center word are defined as in the example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;This&lt;/strong&gt; &lt;em&gt;is a really big text&lt;/em&gt; input you give to the algorithm.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;This&lt;/em&gt; &lt;strong&gt;is&lt;/strong&gt; &lt;em&gt;a really big text input&lt;/em&gt; you give to the algorithm.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;This is&lt;/em&gt; &lt;strong&gt;a&lt;/strong&gt; &lt;em&gt;really big text input you&lt;/em&gt; give to the algorithm.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;This is a&lt;/em&gt; &lt;strong&gt;really&lt;/strong&gt; &lt;em&gt;big text input you give&lt;/em&gt; to the algorithm.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At each step, a word is selected as the center word and words within a certain radius of the center word are context words.&lt;/p&gt;

&lt;p&gt;If the above sentence is the only input you give to the algorithm, you expect the probability of the word "&lt;em&gt;big"&lt;/em&gt; appearing in the context of "&lt;em&gt;text"&lt;/em&gt; to be very high.&lt;/p&gt;

&lt;p&gt;And with a large enough dataset, this algorithm can create a word embedding in which words are closer to each other if they are semantically similar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results: Analogy Example
&lt;/h2&gt;

&lt;p&gt;At the end of the lecture, there is a fascinating use case example for the algorithm.&lt;/p&gt;

&lt;p&gt;Since words are described as vectors via the Word2Vec algorithm, you can apply vector operations on words!&lt;/p&gt;

&lt;p&gt;Firstly, you can ask the algorithm: "What are some similar words to the &lt;strong&gt;banana&lt;/strong&gt;?". And the algorithm gives very accurate results such as "coconut, mongo, bananas".&lt;/p&gt;

&lt;p&gt;Once those vectors are calculated, this is just a question of finding the nearest points on a k-dimensional space. This is easily answered by running the &lt;a href="https://www.ibm.com/topics/knn#:~:text=The%20k%2Dnearest%20neighbors%20algorithm%2C%20also%20known%20as%20KNN%20or,of%20an%20individual%20data%20point."&gt;k-nearest neighbors&lt;/a&gt; - *knn *- algorithm on the word embedding.&lt;/p&gt;

&lt;p&gt;Secondly, you can add or subtract words from each other!&lt;/p&gt;

&lt;p&gt;In the lecture, the following example is given:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;King - Man + Woman = ?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And the algorithm replied correctly with the Queen!&lt;/p&gt;

&lt;p&gt;So, with this algorithm, you can find analogies very easily.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This was a great introduction lecture. If you have read it so far, I strongly suggest you go watch it on &lt;a href="https://www.youtube.com/watch?v=rmVRLeJRkl4&amp;amp;list=PPSV"&gt;YouTube&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I will be sharing a post for each lecture on the list, so stay tuned!&lt;/p&gt;

</description>
      <category>nlp</category>
      <category>chatgpt</category>
      <category>word2vec</category>
      <category>gpt3</category>
    </item>
    <item>
      <title>Top 5 Struggles of Backend Developers</title>
      <dc:creator>mkadirtan</dc:creator>
      <pubDate>Fri, 31 Mar 2023 21:57:18 +0000</pubDate>
      <link>https://dev.to/nooptoday/top-5-struggles-of-backend-developers-1788</link>
      <guid>https://dev.to/nooptoday/top-5-struggles-of-backend-developers-1788</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;"Web is an I/O device"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;...as Uncle Bob describes.&lt;/p&gt;

&lt;p&gt;I/O, Input / Output, *i.e *user input and server output.&lt;/p&gt;

&lt;p&gt;Users want to access some data through applications or websites.&lt;/p&gt;

&lt;p&gt;They want it to be available throughout the world over.&lt;/p&gt;

&lt;p&gt;If the requirements are so simple, why is backend development so challenging? That is a great question I want to &lt;em&gt;hopefully&lt;/em&gt; answer in this post. But more than that, this post should be a grumbling space for hardworking backend developers.&lt;/p&gt;




&lt;p&gt;Let's have a look at a simplistic diagram of a backend server.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnooptoday.com%2Fcontent%2Fimages%2F2023%2F03%2Fimage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnooptoday.com%2Fcontent%2Fimages%2F2023%2F03%2Fimage.png" alt="example http request"&gt;&lt;/a&gt;&lt;br&gt;
Everything looks simple from the outside. But a lot is going on behind the scenes. In the end, it is called "backend" development for a reason.&lt;/p&gt;

&lt;p&gt;The job of a backend developer is to make everything work seamlessly, at least from a user perspective.&lt;/p&gt;

&lt;p&gt;So, here is my list of the top 5 struggles of backend developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Struggle 1: Crashing Servers!
&lt;/h2&gt;

&lt;p&gt;Backend developers need to always remind themselves:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The server can go down at any point in time&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is not only the server, unhandled rejections, network problems, and countless other things can cause application crashes.&lt;/p&gt;

&lt;p&gt;This is a list of &lt;a href="https://www.gremlin.com/community/tutorials/chaos-engineering-the-history-principles-and-practice/#fallacies-of-distributed-systems" rel="noopener noreferrer"&gt;fallacies of distributed systems:&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The network is reliable&lt;/li&gt;
&lt;li&gt;Latency is zero&lt;/li&gt;
&lt;li&gt;Bandwidth is infinite&lt;/li&gt;
&lt;li&gt;The network is secure&lt;/li&gt;
&lt;li&gt;Topology doesn't change&lt;/li&gt;
&lt;li&gt;There is one administrator&lt;/li&gt;
&lt;li&gt;Transport cost is zero&lt;/li&gt;
&lt;li&gt;The network is homogeneous&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are more than an inconvenience for backend development.&lt;/p&gt;

&lt;p&gt;It is already hard to write correctly functioning programs. Now you also need to consider failure scenarios and make the application &lt;strong&gt;fault tolerant.&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnooptoday.com%2Fcontent%2Fimages%2F2023%2F03%2Fimage-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnooptoday.com%2Fcontent%2Fimages%2F2023%2F03%2Fimage-1.png" alt="a meme about developer not understanding why their code works or does not work"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Struggle 2: Scalability
&lt;/h2&gt;

&lt;p&gt;There are various aspects of scalability, but let's keep things simple for the sake of this post.&lt;/p&gt;

&lt;p&gt;A scalable application can continue to work even if the load increases significantly.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnooptoday.com%2Fcontent%2Fimages%2F2023%2F03%2Fdo-you-scale.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnooptoday.com%2Fcontent%2Fimages%2F2023%2F03%2Fdo-you-scale.jpeg" alt="a meme for comparing vertical scaling and horizontal scaling"&gt;&lt;/a&gt;&lt;br&gt;
Servers have limited capacity and they can handle only a limited amount of requests.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you add more resources to the server it can handle more requests ( &lt;em&gt;vertical scaling&lt;/em&gt; ).&lt;/li&gt;
&lt;li&gt;If you add more servers to the system they can handle more requests ( &lt;em&gt;horizontal scaling ).&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Designing an application to be horizontally scalable, immediately changes the way things work.&lt;/p&gt;

&lt;p&gt;As an example, most of the backend developers make race condition mistakes in scalable applications - *including myself. *In a scalable application, data can be read or modified by multiple servers. A typical example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Server A reads the data &lt;code&gt;{ foo: 1 }&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Server B reads the data &lt;code&gt;{ foo: 1 }&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Server A modifies the data and writes back: &lt;code&gt;{ foo: 1, bar: 2 }&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Server B modifies the data and writes back: &lt;code&gt;{ foo: 1, baz: 2  }&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result can be either &lt;code&gt;{ foo: 1, bar: 2 }&lt;/code&gt; or &lt;code&gt;{ foo: 1, baz: 2  }&lt;/code&gt; depending on which server writes back the data last. So, both servers are in a &lt;a href="https://www.techtarget.com/searchstorage/definition/race-condition" rel="noopener noreferrer"&gt;&lt;strong&gt;race condition&lt;/strong&gt;!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was just an example, but there are a lot of things to consider when developing a horizontally scalable application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Struggle 3: Security
&lt;/h2&gt;

&lt;p&gt;Remember, a public server is accessible to everyone on the internet.&lt;/p&gt;

&lt;p&gt;And, there are a lot of bad actors out there 🥷.&lt;/p&gt;

&lt;p&gt;Bad actors can craft special requests to extract information from a vulnerable server.&lt;/p&gt;

&lt;p&gt;Go check out &lt;a href="https://owasp.org/www-project-top-ten/" rel="noopener noreferrer"&gt;https://owasp.org/www-project-top-ten/&lt;/a&gt; for what kind of sorcery those bad actors do to your servers.&lt;/p&gt;

&lt;p&gt;Even legitimate users should be considered bad actors from a backend developer's perspective.&lt;/p&gt;

&lt;p&gt;Legitimate users may abuse the service or send unexpected inputs to exploit the server's vulnerabilities. All user inputs should be sanitized to prevent unexpected inputs from legitimate users. Schema definitions, such as JSON Schema, are very helpful to sanitize user input.&lt;/p&gt;

&lt;p&gt;Also, legitimate users are not allowed to do anything they want. The service needs to have a well-defined authorization system to prevent users from accessing forbidden resources.&lt;/p&gt;

&lt;p&gt;The server might be vulnerable to a &lt;em&gt;Denial of Service&lt;/em&gt; attack. Most DoS attacks can be prevented with rate limiting.&lt;/p&gt;

&lt;p&gt;The list goes on, and the truth is no server can be 100% secure. Try to follow best practices as much as possible to secure your servers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Struggle 4: Consistency
&lt;/h2&gt;

&lt;p&gt;If a car is red, then it is red.&lt;/p&gt;

&lt;p&gt;Other people should also tell you that car is red.&lt;/p&gt;

&lt;p&gt;And, nobody should say that car isn't red.&lt;/p&gt;

&lt;p&gt;Then tell me in the comments...&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnooptoday.com%2Fcontent%2Fimages%2F2023%2F03%2Fimage-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnooptoday.com%2Fcontent%2Fimages%2F2023%2F03%2Fimage-2.png" alt="the dress which often cause confusion about its colors"&gt;&lt;/a&gt;&lt;a href="https://en.wikipedia.org/wiki/The_dress" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/The_dress&lt;/a&gt;&lt;br&gt;
...what is the color of this dress? Is it black &amp;amp; blue or white &amp;amp; gold? Whichever you choose, you would be surprised to see other people swear it is the other one! &lt;/p&gt;

&lt;p&gt;You see, sometimes it is not very easy to come up with a single true answer to such a basic question.&lt;/p&gt;

&lt;p&gt;In computer terms, this dress can be a document read from a cache, a slow replicate instance of a database, or an event-sourced database.&lt;/p&gt;

&lt;p&gt;In all cases, the data might be obsolete. One server might read obsolete data while the other has access to a more recent version of the document.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trade-off: Consistency and Performance
&lt;/h3&gt;

&lt;p&gt;The problem with consistency is that retrieving the latest information may not be the optimum solution for most cases.&lt;/p&gt;

&lt;p&gt;For example, if thousands of people try to access a popular tweet at the same time what do they see? The same tweet content, except the read counts, are probably way different from each other.&lt;/p&gt;

&lt;p&gt;This is the result of a design decision. The engineers at Twitter decided to trade off between performance and consistency at the expense of showing obsolete read counts. This is a pretty good deal because the read counts are not a critical part of the tweets.&lt;/p&gt;

&lt;h3&gt;
  
  
  More About Consistency
&lt;/h3&gt;

&lt;p&gt;Well, sometimes inconsistencies happen not because of design decisions but because of the way things work in software engineering.&lt;/p&gt;

&lt;p&gt;Remember the previous example about the race condition? Well, how do you handle that? You might use locks but that can be costly ( in terms of time ). Some systems use optimistic locking to get better results. Some other systems use event sourcing and evade the problem completely.&lt;/p&gt;

&lt;p&gt;Then there is the problem with client and backend consistency. The client database should be consistent with the actual data on the backend. Here is a nice article if you want to read more about consistency: &lt;a href="https://medium.com/ssense-tech/handling-eventual-consistency-with-distributed-system-9235687ea5b3" rel="noopener noreferrer"&gt;https://medium.com/ssense-tech/handling-eventual-consistency-with-distributed-system-9235687ea5b3&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Struggle 5: Performance
&lt;/h2&gt;

&lt;p&gt;I think this one is pretty obvious. Everyone wants to develop blazingly fast backend applications.&lt;/p&gt;

&lt;p&gt;But, that is not an easy task. From the language and framework selection to the algorithms used and the overall design of the system, almost everything has an impact on the performance.&lt;/p&gt;

&lt;p&gt;I would say, the best course of action is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use a performance testing tool such as &lt;a href="https://k6.io/" rel="noopener noreferrer"&gt;k6&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Don't waste time ultra-optimizing the application if it meets the criteria&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It is that simple...&lt;/p&gt;

&lt;p&gt;...to give advice from a blog post 😅&lt;/p&gt;

&lt;p&gt;In reality, measuring the application performance is somewhat complicated. Maybe you can easily measure the end-to-end performance of your endpoints etc.&lt;/p&gt;

&lt;p&gt;But detecting the actual bottleneck in your application is hard without observability tools.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In RESTful backend applications, a for loop or a basic algorithm in the code is rarely the bottleneck. Optimizing the database queries, network configurations, or API design usually have greater benefits.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The struggle is real for the backend developers. Share your struggles in the comments and show others they are not alone!&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this post, subscribe for more like this.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>performance</category>
      <category>development</category>
      <category>scalability</category>
    </item>
    <item>
      <title>Reduce Network Usage - With This 1 Simple Trick!</title>
      <dc:creator>mkadirtan</dc:creator>
      <pubDate>Mon, 27 Mar 2023 04:15:00 +0000</pubDate>
      <link>https://dev.to/nooptoday/reduce-network-usage-with-this-1-simple-trick-1k2h</link>
      <guid>https://dev.to/nooptoday/reduce-network-usage-with-this-1-simple-trick-1k2h</guid>
      <description>&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@helloimnik?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Nik&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Making efficient use of the network is essential.&lt;/p&gt;

&lt;p&gt;Efficient applications work faster and smoother, even in low network conditions.&lt;/p&gt;

&lt;p&gt;Efficiency can be achieved in two stages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Design time&lt;/li&gt;
&lt;li&gt;Runtime&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You might not want to mess with the design part if the application is already designed and actively running.&lt;/p&gt;

&lt;p&gt;Then, there is this approach with application development: &lt;strong&gt;you should not optimize early.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Runtime optimizations can reduce network usage to a desired level. If that is the case, optimizing the design can be considered an &lt;strong&gt;early optimization.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Design Time Optimizations
&lt;/h3&gt;

&lt;p&gt;Design time optimizations for network usage relate to the overall design of how the application interacts with network resources.&lt;/p&gt;

&lt;p&gt;For example, using GraphQL can reduce network usage for many applications. The reason is, GraphQL allows applications to fetch only the required amount of data and nothing else.&lt;/p&gt;

&lt;p&gt;Some applications access the backend via BFF - *&lt;a href="https://blog.bitsrc.io/bff-pattern-backend-for-frontend-an-introduction-e4fa965128bf"&gt;Backend for Frontend&lt;/a&gt;. *This can also help reduce network usage from the application point of view. The BFF can aggregate data from multiple servers and serve it to the application through a single API call.&lt;/p&gt;

&lt;p&gt;These are some of the optimizations you can consider to reduce network usage in the design stage.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Going beyond the REST, and creating optimized API endpoints&lt;/li&gt;
&lt;li&gt;Keeping request/response schemas as little as possible&lt;/li&gt;
&lt;li&gt;Using efficient data structures - &lt;em&gt;such as protocol buffers&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Runtime Optimizations
&lt;/h3&gt;

&lt;p&gt;Runtime optimizations relate to the smartness of the applications.&lt;/p&gt;

&lt;p&gt;For example, a &lt;strong&gt;smart application&lt;/strong&gt; shouldn't request the same resource twice. This can be achieved by implementing caching strategies&lt;/p&gt;

&lt;p&gt;Caching is one of the most popular solutions to reduce network usage and network latency as well.&lt;/p&gt;

&lt;p&gt;Despite its popularity, there is no ready-to-go solution for caching. Applications should use the correct caching strategies depending on the use case. In fact, caching is one of the hardest things in software development. Remember the famous quote:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are only two hard things in computer science: cache invalidation and naming things. - Phil Karlton&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With the increasing popularity of reactive programming, there are some clever tricks to reduce the number of network calls.&lt;/p&gt;

&lt;p&gt;For example, imagine the application has a search box that shows the results in real-time. Instead of sending search requests after every time a letter is typed, the applications use a **debounce **operator. Debounce operator sends a search request after the user stops typing.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Simple Trick: Compression
&lt;/h3&gt;

&lt;p&gt;Wait, did you make me read the article just to let me know about compression?&lt;/p&gt;

&lt;p&gt;Don't get frustrated, I have a good reason to do so! Besides, I talk about other things, too. Bear with me 🧸&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You might be using compression wrong.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Compression is very simple to use because there are already well-known algorithms you can use out of the box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem is compressing the encrypted data.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You should &lt;strong&gt;never compress the encrypted data&lt;/strong&gt;, because you simply can't. The compressed data is hardly smaller than the original and the applications waste CPU cycles for compression 😮.&lt;/p&gt;

&lt;p&gt;Instead, you should &lt;strong&gt;always encrypt the compressed data.&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  How to Tell If My Application Make It Right?
&lt;/h4&gt;

&lt;p&gt;Simply, toggle the compression on / off and compare the payload sizes. If the payload sizes are very close, then your application probably encrypts first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Payload Comparison: Compress First vs. Encrypt First
&lt;/h3&gt;

&lt;p&gt;To make comparison easier, I created a small example repository.&lt;/p&gt;

&lt;p&gt;The example uses &lt;code&gt;aes-256-cbc&lt;/code&gt; as the encryption method and &lt;code&gt;brotli&lt;/code&gt; as the compression algorithm. You can also check the example in &lt;a href="https://github.com/nooptoday/compression-encryption-order"&gt;GitHub&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[      resource ] http://jsonplaceholder.typicode.com/albums?userId=1
[      original ] 816
[  encryptFirst ] 746
[ compressFirst ] 244
[  % difference ] 67.29 reduction


[      resource ] http://jsonplaceholder.typicode.com/albums
[      original ] 9333
[  encryptFirst ] 7472
[ compressFirst ] 1723
[  % difference ] 76.94 reduction


[      resource ] http://jsonplaceholder.typicode.com/photos
[      original ] 1071472
[  encryptFirst ] 820717
[ compressFirst ] 98447
[  % difference ] 88.00 reduction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why Compression Doesn't Work After Encryption?
&lt;/h3&gt;

&lt;p&gt;The reason is simple. Compression algorithms try to represent the same data with fewer bytes.&lt;/p&gt;

&lt;p&gt;They first try to identify repeating patterns or some kind of order in the original data. If the original data contains the word &lt;code&gt;lorem ipsum&lt;/code&gt; 5 times, the compressed data replaces all recurring occurrences with references to the first occurence.&lt;/p&gt;

&lt;p&gt;The responsibility of encryption algorithms is to break recognizable patterns in the original data. They scrumble the data so that it can't be understood by external actors. They create a high entropy representation of the original data, in cryptography terms.&lt;/p&gt;

&lt;p&gt;Essentially, an encrypted data loses its recognizable patterns and it becomes harder to compress.&lt;/p&gt;

&lt;p&gt;A real life equivalent could be a shopping list.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Egg&lt;/li&gt;
&lt;li&gt;Egg&lt;/li&gt;
&lt;li&gt;Egg&lt;/li&gt;
&lt;li&gt;Egg&lt;/li&gt;
&lt;li&gt;Egg&lt;/li&gt;
&lt;li&gt;Milk&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can easily remember this list easily, because it comes down to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5 x Egg&lt;/li&gt;
&lt;li&gt;Milk&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But that is not possible with the following list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Egg&lt;/li&gt;
&lt;li&gt;Milk&lt;/li&gt;
&lt;li&gt;Bread&lt;/li&gt;
&lt;li&gt;Apples&lt;/li&gt;
&lt;li&gt;Lemons&lt;/li&gt;
&lt;li&gt;Chocolate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even though there are same amount of items in both lists, the second list can't be compressed. That is what encryption does to compression. &lt;/p&gt;

&lt;h3&gt;
  
  
  Further Reading
&lt;/h3&gt;

&lt;p&gt;Check out these articles for further reading:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.geeksforgeeks.org/difference-between-data-encryption-and-data-compression/"&gt;https://www.geeksforgeeks.org/difference-between-data-encryption-and-data-compression/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.encryptionconsulting.com/education-center/encryption-and-compression/"&gt;https://www.encryptionconsulting.com/education-center/encryption-and-compression/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As an additional note, there are some security concerns regarding compression. But that is out of scope of this post.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>backend</category>
      <category>compression</category>
      <category>encryption</category>
    </item>
    <item>
      <title>FeathersJS vs NestJS - Compared in 3 Key Areas</title>
      <dc:creator>mkadirtan</dc:creator>
      <pubDate>Mon, 13 Mar 2023 07:05:58 +0000</pubDate>
      <link>https://dev.to/nooptoday/feathersjs-vs-nestjs-compared-in-3-key-areas-35a1</link>
      <guid>https://dev.to/nooptoday/feathersjs-vs-nestjs-compared-in-3-key-areas-35a1</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover photo by &lt;a href="https://unsplash.com/@wacalke?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;Mateusz Wacławek&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.feathersjs.com/introducing-feathers-5-the-api-and-real-time-application-framework-101ae2deaaeb"&gt;FeathersJS released its 5th major version, a.k.a Dove recently&lt;/a&gt;, and I've been watching the framework for some time. It is an excellent time to compare two backend framework giants, FeathersJS and NestJS. These are not your "yet another javascript framework" type of framework. They pave the way to backend development in the Node.js environment.&lt;/p&gt;




&lt;p&gt;In my opinion, Node.js provides a very powerful backend software development environment. A typical backend application accepts requests, executes queries on the database, and writes some files to disk. All of these tasks can be handled asynchronously in Node.js, meaning the server can handle many requests at the same time. Even though you can achieve the same or better results in other languages, it is easier to write asynchronous code in Javascript.&lt;/p&gt;

&lt;p&gt;The struggle in the Node.js world is &lt;strong&gt;standardization.&lt;/strong&gt; You have too many options to choose from, due to the large number of npm packages and the community size. You can find new javascript framework releases every other week, or someone in the community sharing their way of building applications. Don't get me wrong, I'm happy to be in such an active community but this is a double-edged sword.&lt;/p&gt;

&lt;p&gt;FeathersJS and NestJS both provide a structure for writing backend applications with their techniques. Both of them are capable of creating the same applications however their style differs a lot.&lt;/p&gt;

&lt;p&gt;In this post, I will be comparing FeathersJS and NestJS from a developer experience perspective on key areas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Application Structure
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Application Structure - FeathersJS
&lt;/h3&gt;

&lt;p&gt;To create a new FeathersJS application, execute this in your terminal: &lt;code&gt;npm create feathers&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the application creation process, FeathersJS CLI allows for many customizations such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;TypeScript or JavaScript&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;KoaJS or Express&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;Will you build a &lt;code&gt;REST application, Real-time application or all off them&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Which package manager to use &lt;code&gt;npm, yarn, pnpm&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;What is your preferred schema definition format &lt;code&gt;TypeBox or JSON Schema&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Which databases will you connect to &lt;code&gt;SQLite, MongoDB, PostgreSQL, MySQL/MariaDB, MicrosoftSQL&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Select authentication mechanisms &lt;code&gt;Email + Password, Google, Facebook, Twitter, Github and Auth0&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feathers-app/
├── config/
│   ├── custom-environment-variables.json
│   ├── default.json
│   └── test.json
├── knexfile.ts
├── migrations/
│   ├── 20230205130353_user.ts
│   └── 20230205130403_authentication.ts
├── package-lock.json
├── package.json
├── public/
│   └── index.html
├── readme.md
├── src/
│   ├── app.ts
│   ├── authentication.ts
│   ├── channels.ts
│   ├── client.ts
│   ├── configuration.ts
│   ├── declarations.ts
│   ├── hooks/
│   │   └── log-error.ts
│   ├── index.ts
│   ├── logger.ts
│   ├── services/
│   │   ├── index.ts
│   │   └── users/
│   │       ├── users.class.ts
│   │       ├── users.schema.ts
│   │       ├── users.shared.ts
│   │       └── users.ts
│   ├── sqlite.ts
│   └── validators.ts
├── test/
│   ├── app.test.ts
│   ├── client.test.ts
│   └── services/
│       └── users/
│           └── users.test.ts
└── tsconfig.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;FeathersJS application folder structure, automatically generated by CLI&lt;br&gt;
FeathersJS application folder structure allows developers to easily decide where to put new files. It is well-structured and easily recognizable.&lt;/p&gt;

&lt;p&gt;FeathersJS's preferred style of writing applications revolves around the idea of &lt;strong&gt;services&lt;/strong&gt;. If you want to introduce new functionality in your application, you are most likely going to create a new &lt;strong&gt;service&lt;/strong&gt; in FeathersJS.&lt;/p&gt;

&lt;p&gt;Other than that, core functionalities such as authentication, routing, logging, and validation are well-defined in FeathersJS. You are very likely to use existing solutions provided by the framework with little configuration.&lt;/p&gt;

&lt;p&gt;One thing that makes FeathersJS special is, it can &lt;strong&gt;generate its client code automatically.&lt;/strong&gt; This is a unique feature I've never heard before - &lt;em&gt;correct me if I am wrong on this.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Another special feature of FeathersJS is that it has the concept of &lt;strong&gt;channels&lt;/strong&gt;. Which allows clients or other servers running your code to get notified about certain events. It is almost an in-app message broker on the server side. I'm not sure about the scalability of channels though! This is a very neat feature considering FeathersJS calls itself: &lt;a href="https://feathersjs.com/"&gt;The API and Real-time&lt;br&gt;
Application Framework.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Least but not least, you can replace almost all 3rd party npm packages in FeathersJS to your taste. You might want to use another validation library or logging library, BUT you will never want to worry about your HTTP server library. FeathersJS HTTP server works fast and its &lt;strong&gt;performance is not dependent on the underlying HTTP server&lt;/strong&gt;, read more about this here: &lt;a href="https://feathersjs.com/guides/whats-new.html#lightning-fast-routing"&gt;Lightning Fast Routing&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Application Structure - NestJS
&lt;/h3&gt;

&lt;p&gt;To create a new NestJS application, execute this on your terminal: &lt;code&gt;nest new my-project&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;NestJS doesn't provide many customizations through CLI but it has guides for customizations such as switching HTTP adapters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nest-app/
├── README.md
├── nest-cli.json
├── package-lock.json
├── package.json
├── src/
│   ├── app.controller.spec.ts
│   ├── app.controller.ts
│   ├── app.module.ts
│   ├── app.service.ts
│   ├── main.ts
│   └── user/
│       ├── dto/
│       │   ├── create-user.dto.ts
│       │   └── update-user.dto.ts
│       ├── entities/
│       │   └── user.entity.ts
│       ├── user.controller.spec.ts
│       ├── user.controller.ts
│       ├── user.module.ts
│       ├── user.service.spec.ts
│       └── user.service.ts
├── test/
│   ├── app.e2e-spec.ts
│   └── jest-e2e.json
├── tsconfig.build.json
└── tsconfig.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NestJS application folder structure, automatically generated by CLI&lt;br&gt;
NestJS has a very modular project structure which is also reflected in its folder structure.&lt;/p&gt;

&lt;p&gt;NestJS's preferred style of writing applications revolves around the idea of &lt;strong&gt;modules&lt;/strong&gt;. Modules contain providers and controllers, they can import other modules or export their providers, and they are configurable, read more about it in the previous post: &lt;a href="https://nooptoday.com/dynamic-modules-in-nestjs/"&gt;Best Way to Create Dynamic Modules in NestJS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The business logic of a NestJS application usually resides in &lt;strong&gt;services&lt;/strong&gt;. A service can use other services via &lt;strong&gt;dependency injection&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Implementation details of the NestJS framework are mostly hidden from the developers. &lt;strong&gt;NestJS exposes most of its functionality via Typescript decorators&lt;/strong&gt;. If you are into code aesthetics you can prefer this style of coding, and read more about it in the previous post: &lt;a href="https://nooptoday.com/custom-decorators-in-nestjs/"&gt;Custom Decorators in NestJS&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since NestJS doesn't allow much customization it is easy for other NestJS developers to adapt your project easily.&lt;/p&gt;

&lt;p&gt;A unique approach NestJS brings to backend application development is using reactive programming for most things. You can see &lt;strong&gt;Observables being used in HTTP requests, events, commands anything you name.&lt;/strong&gt; This might be an innovative approach but in my experience, observables cause a performance drop in NestJS applications.&lt;/p&gt;

&lt;p&gt;Similar to FeathersJS, core functionalities are well-defined and you can find resources for whatever you want to do in a NestJS application. NestJS can be considered a little more mature compared to FeathersJS.&lt;/p&gt;

&lt;p&gt;NestJS is also customizable but due to the way adapters are written, sometimes using a different package can cause a loss of functionality. For example, it is known that &lt;strong&gt;you lose functionality by switching from Express Adapter to Fastify Adapter,&lt;/strong&gt; but this is a minor inconvenience for most developers.&lt;/p&gt;

&lt;p&gt;Last but not least, &lt;strong&gt;NestJS CLI is capable of managing a monorepo project structure.&lt;/strong&gt; Which is very helpful if you are doing &lt;strong&gt;microservices&lt;/strong&gt; with NestJS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Customization Options
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Customization Options - FeathersJS
&lt;/h3&gt;

&lt;p&gt;FeathersJS is intentionally made to be very customizable. There are two reasons for that.&lt;/p&gt;

&lt;p&gt;Firstly, if you are already developing your backend application in ExpressJS, you can just switch ExpressJS with FeathersJS and your project will work just fine. From there on, you can make the full switch bit by bit. This allows an easier migration path for projects that use ExpressJS.&lt;/p&gt;

&lt;p&gt;Secondly, FeathersJS doesn't want to have opinions about how you implement your application. Rather, it aims to lay out best practices and its own implementations for them. It has good solutions that work well, and you can use them whenever you want to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Customization Options - NestJS
&lt;/h3&gt;

&lt;p&gt;NestJS is intentionally made to be less customizable. &lt;/p&gt;

&lt;p&gt;NestJS aims to be the framework for enterprise applications. Enterprises don't like custom solutions. Custom solutions are costly to enterprise because it requires the knowledge of the person who implemented them. Developers can come and go, the project shouldn't be affected by this.&lt;/p&gt;

&lt;p&gt;Also, we shouldn't forget NestJS is heavily inspired by AngularJS and it is also one of the less customizable frameworks for frontend.&lt;/p&gt;

&lt;p&gt;BUT, this doesn't mean you can't customize your project or every other NestJS developer can immediately start working on existing NestJS projects. The reality is you can customize, but you shouldn't do it. Even if you do leave tracks of the NestJS railway, you will probably go back to the track for using some other functionality to work. Let me make it clear with a simple example:&lt;/p&gt;

&lt;p&gt;You can opt out of the class-validator library in NestJS and use AJV for validation. It works without causing you problems but now you can't use automatic OpenAPI generation in NestJS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Community and Documentation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Community and Documentation - FeathersJS
&lt;/h3&gt;

&lt;p&gt;FeathersJS has a small, helpful, and welcoming community. You can join the community in Discord. One thing very noticeable on the FeathersJS website is the &lt;a href="https://feathersjs.com/ecosystem/"&gt;Ecosystem&lt;/a&gt; page where community-driven FeathersJS packages are promoted!&lt;/p&gt;

&lt;p&gt;FeathersJS documentation walks you through everything you need in the framework. It is simple and clear. There are a few amounts of blog posts or online courses for FeathersJS, but I think numbers will go up after the latest release. David Luecke and other core maintainers are putting a lot of effort into the framework for some time, and I hope they get more recognition in the Node.js ecosystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Community and Documentation - NestJS
&lt;/h3&gt;

&lt;p&gt;NestJS has a large, helpful, and welcoming community. You can join the community in Discord. NestJS has official online courses &lt;a href="https://courses.nestjs.com/"&gt;that can be purchased on its website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I don't know how popular is their course but documentation on their website can get you through most of the things. To solve some problems you might need help from StackOverflow or GitHub issues but other than that, I think documentation and examples are enough. Can't skip here without mentioning &lt;a href="https://www.udemy.com/course/nestjs-zero-to-hero/"&gt;NestJS Hero to Zero&lt;/a&gt; online course by Ariel Weinberger, which I've completed and found helpful.&lt;/p&gt;

&lt;p&gt;I haven't had time to review the new &lt;a href="https://devtools.nestjs.com/login"&gt;Developer Tools&lt;/a&gt; by NestJS, but it looks like a very helpful tool. It is a paid tool by NestJS but at a low price. I think it would be much better if they released it for free at least initially.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;You can build applications of any size and functionality whichever you choose. To choose between FeathersJS and NestJS means choosing between two different code styles. In my opinion, the development process in FeathersJS feels more fitting ( natural ) to the Node.js environment, but, I also understand the reason why NestJS is preferred by enterprise applications.&lt;/p&gt;

&lt;p&gt;Mad respect to both David Luecke and Kamil Mysliwiec and all the other contributors, and maintainers of both projects for creating two of the strongest backend frameworks for Node.js.&lt;/p&gt;

&lt;p&gt;If you have experience in either of the frameworks, I would like to know what you think, please share your experiences and opinions in the comment section.&lt;/p&gt;

&lt;p&gt;I hope you learned something new, have a good one!&lt;/p&gt;

</description>
      <category>feathersjs</category>
      <category>nestjs</category>
      <category>node</category>
      <category>backend</category>
    </item>
    <item>
      <title>Scalable Websocket Server Implemented by ChatGPT</title>
      <dc:creator>mkadirtan</dc:creator>
      <pubDate>Wed, 01 Feb 2023 07:30:00 +0000</pubDate>
      <link>https://dev.to/nooptoday/scalable-websocket-server-implemented-by-chatgpt-15p1</link>
      <guid>https://dev.to/nooptoday/scalable-websocket-server-implemented-by-chatgpt-15p1</guid>
      <description>&lt;p&gt;Cover photo by &lt;a href="https://unsplash.com/@possessedphotography" rel="noopener noreferrer"&gt;possessedphotography&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the previous post &lt;a href="https://nooptoday.com/why-websockets-are-hard-to-scale/" rel="noopener noreferrer"&gt;Why Websockets are Hard to Scale&lt;/a&gt; we've talked about the problems with scaling websockets and some of the existing solutions as well. The post mentioned using a load balancing technique called consistent hashing, which is a very elegant solution to this problem. I promised you for a post about how to implement scalable websocket server with consistent hashing.&lt;/p&gt;

&lt;p&gt;Well, the day has come, take your coffee and follow along. Special thanks to ChatGPT, almost all of the code you will find in this post is written by ChatGPT. I only made some adjustments, so the code actually works.&lt;/p&gt;




&lt;p&gt;The plan is to use code generated by ChatGPT, and do as little modifications as possible on it. If you've read the previous post I'm sure you have an outline of what we will do. But to remind you again here are steps for our implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a websocket server&lt;/li&gt;
&lt;li&gt;Create a hashring with server addresses, update when necessary&lt;/li&gt;
&lt;li&gt;Retrieve list of servers, and keep it updated for all servers&lt;/li&gt;
&lt;li&gt;Redirect clients to correct servers&lt;/li&gt;
&lt;li&gt;Extra: Create a client that can redirect itself&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  New favourite IDE unlocked: The Prompter
&lt;/h3&gt;

&lt;p&gt;I was reluctant to test out the ChatGPT but it turns out to be very helpful, intelligent enough to give me code blocks that I can work on but still dumb enough to take my job ^^. Whether we like it or not, it is already here. As with all other technologies if you embrace it sooner than later, you can use it for your advantage. At least that is what I realized with my experience.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ChatGPT can be challenging to work with at times, but with practice and by using more specific prompts, it is possible to unlock its full potential. I recommend you to have a look at &lt;a href="https://github.com/f/awesome-chatgpt-prompts" rel="noopener noreferrer"&gt;awesome-chatgpt-prompts&lt;/a&gt; by my dear colleague, Fatih Kadir Akın, for inspiration on how to effectively communicate with ChatGPT.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  How to Better Use ChatGPT for Code Generation
&lt;/h2&gt;

&lt;p&gt;Since ChatGPT will not create a fully completed project for us, each implementation step covers a single concept. Therefore we can get a working code block for each step and glue them together!&lt;/p&gt;

&lt;h3&gt;
  
  
  Hashring Implementation
&lt;/h3&gt;

&lt;p&gt;I've started with the hashring, and asked ChatGPT to create me a hashring implementaiton in TypeScript, with support for virtual nodes. The first output from ChatGPT seemed okay but it used a &lt;code&gt;&amp;gt;&lt;/code&gt; comparison for strings. Also, the hash algorithm didn't create random and even results. First, I asked for fixing the bug with &lt;code&gt;&amp;gt;&lt;/code&gt; comparison. Then, I wanted it to use a hash function with better distribution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createHash&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crypto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HashRing&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;replicas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;replicas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replicas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;replicas&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ring&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

    &lt;span class="c1"&gt;// Create a hash for each node and add it to the ring&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;replicas&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Sort the keys in the ring to ensure that they are in clockwise order&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sortedKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;localeCompare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Get the node responsible for a given key&lt;/span&gt;
  &lt;span class="nf"&gt;getNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sortedKeys&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Find the first node with a position greater than the hash&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findIndex&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;localeCompare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;numeric&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// If no such node is found, the key belongs on the first node&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that complete, I copied the code into &lt;code&gt;hashring.ts&lt;/code&gt; and exported the class. Whenever the server list is updated, this class will be recreated. Then we can iterate through all the connected sockets and send them a redirect message if they are not supposed to be on this server.&lt;/p&gt;

&lt;p&gt;Full conversation with hashring implementation: &lt;a href="https://sharegpt.com/c/kxhBEp6" rel="noopener noreferrer"&gt;https://sharegpt.com/c/kxhBEp6&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Websocket Server Implementation
&lt;/h3&gt;

&lt;p&gt;Next up, I requested ChatGPT to create a Websocket server. It immediately created a Hello World example using &lt;code&gt;ws&lt;/code&gt; library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ws&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;wss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Received message =&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello! Message From Server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ChatGPT has a tendency for not using default imports, but it is easy to fix. With the basic server setup, I requested ChatGPT to add feature for redirecting clients based on hashring algorithm.&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;serverList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;server1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;server2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;server3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientIp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;md5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientIp&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;serverList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;serverList&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientIp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;192.168.0.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientIp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Redirecting client to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But my request was a little unclear, so the output had the general idea but it was missing server and client interaction. So, I wanted ChatGPT to merge two outputs. After a few prompts it created a working example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ws&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crypto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;serverList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;server1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;server2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;server3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientIp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;md5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientIp&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;serverList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;serverList&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;wss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientIp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;upgradeReq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientIp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Redirecting client &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;clientIp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`You have been redirected to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Received message from &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;clientIp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; =&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example was looking OK, but sending a plain text message to clients is not very flexible. So, I asked the ChatGPT to use a more managable message body. Also, it was sending redirect message whether the client was on correct server or not, so I wanted ChatGPT to fix that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ws&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crypto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;serverList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;server1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;server2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;server3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientIp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;md5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientIp&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;serverList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;serverList&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;wss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientIp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;upgradeReq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;correctServer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientIp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Client &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;clientIp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; should be connected to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;correctServer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;upgradeReq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;correctServer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Redirecting client &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;clientIp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;correctServer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redirect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;correctServer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Client &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;clientIp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is already connected to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;correctServer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Received message from &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;clientIp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; =&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Voila! This looks great but there are still more work to do. For example, the server list in this example is static, and we need to manually replace &lt;code&gt;getServer&lt;/code&gt; function with the &lt;code&gt;getNode&lt;/code&gt; method from &lt;code&gt;Hashring&lt;/code&gt;. One amazing side note, I asked the ChatGPT if it can create a client side example that can interact with this server. And it did, it is a very intelligent tool that will amaze me for a long time.&lt;/p&gt;

&lt;p&gt;Full conversation with websocket server and websocket client implementation: &lt;a href="https://sharegpt.com/c/pIc7amA" rel="noopener noreferrer"&gt;https://sharegpt.com/c/pIc7amA&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;WebSocket&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ws&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ws://localhost:8080&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Connected to WebSocket server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redirect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Received redirect message. Disconnecting from current server and connecting to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`ws://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:8080`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Received message =&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Disconnected from WebSocket server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Another important thing to note: Code examples from ChatGPT are not flawless, and I don't think they were meant to be. Sometimes they are easily noticable by IDEs or humans, but sometimes ChatGPT does something very unusual and doesn't work in any way. In that case, you can always ask it to fix its own code, and to my surprise again, it does a good job at it, too!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Implementing Service Registry
&lt;/h3&gt;

&lt;p&gt;To create a hashring, we need addresses of all the available servers. This might sound simple, but it is really difficult to implement such things on the servers. You have to consider failure scenarios and update notifications etc. That is out of scope of this post, but as a simpler solution I was ready to use a 3rd party service registry solution. The problem is, I've never used a service registry before.&lt;/p&gt;

&lt;p&gt;At first, I asked ChatGPT to create a service registry implementation in TypeScript. It created a solution using Redis, but the code looked too complicated to me and I didn't want to use it. Instead I've found myself having a conversation with ChatGPT about which Service Registry Tools are there, what are their differences etc. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;**Me: **can you compare eureka, zookeeper and consul&lt;/p&gt;

&lt;p&gt;**ChatGPT: **Sure! &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Eureka, Zookeeper, and Consul are all tools that can be used for service discovery in a distributed environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Eureka is a REST-based service that is primarily used in the Java ecosystem for locating services for the purpose of load balancing and failover of middle-tier servers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Apache Zookeeper is a distributed coordination service that enables distributed applications to achieve high availability. Zookeeper helps to coordinate distributed applications by providing a central place for them to store and access shared data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Consul is a distributed, highly available, and data center aware tool that can be used for service discovery, configuration, and orchestration. It is written in the Go programming language and provides a HTTP API for interacting with it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In summary, Eureka is primarily used in the Java ecosystem, Zookeeper is a distributed coordination service, and Consul is a tool that can be used for service discovery, configuration, and orchestration.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then I asked about simple examples using each one of the tools. In the end, &lt;code&gt;Consul&lt;/code&gt; seemed like a good solution for this purpose and as an added bonus it was written in &lt;code&gt;Go&lt;/code&gt;, so I gave it a try.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Consul&lt;/code&gt; implementation from ChatGPT didn't work. Even though I asked ChatGPT to fix the code, something was not right. I didn't want to debug and fix it but I was wanting to use as much code from ChatGPT. Problem was much likely due to breaking changes from npm package ( ChatGPT doesn't have up-to-date information on everything ).&lt;/p&gt;

&lt;p&gt;So, what did I do? I went back to square one and asked for a Redis implementation, but this time I asked for Service Discovery instead of Service Registry. Appearantly, I was asking for something slightly different - &lt;a href="https://stackoverflow.com/questions/44540545/microservices-what-is-difference-between-service-registry-and-service-discovery" rel="noopener noreferrer"&gt;related SO post&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Redis&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ioredis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Redis&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;127.0.0.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updateInterval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// in seconds&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;heartbeatInterval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// in seconds&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;serviceList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;heartbeatIntervals&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;NodeJS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Timeout&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;registerServiceInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sadd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;service-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;alive&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EX&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;heartbeatInterval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;heartbeatIntervals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;alive&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EX&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;heartbeatInterval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;heartbeatInterval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;deregisterServiceInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;srem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;service-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;del&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;heartbeatIntervals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;heartbeatIntervals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;removeStaleServiceInstances&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;instances&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;smembers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;service-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ttl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ttl&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;ttl&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;srem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;service-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateServiceList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;instances&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;smembers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;service-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;serviceList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;serviceList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;removeStaleServiceInstances&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateInterval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updateServiceList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateInterval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to raw service discovery implementation, I also asked for automatic update and removing stale services. And it did a great job at creating them, too.&lt;/p&gt;

&lt;p&gt;Full conversation with service discovery implementation: &lt;a href="https://sharegpt.com/c/bGUAItM" rel="noopener noreferrer"&gt;https://sharegpt.com/c/bGUAItM&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it All Together: Scalable Websocket Server
&lt;/h2&gt;

&lt;p&gt;So far we've implemented:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hashring, for determining which server a user belongs to,&lt;/li&gt;
&lt;li&gt;Service Discovery to keep list of available servers,&lt;/li&gt;
&lt;li&gt;Websocket Server for clients to connect,&lt;/li&gt;
&lt;li&gt;Websocket API for re-routing clients when necessary,&lt;/li&gt;
&lt;li&gt;Websocket Client to connect our servers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;with the help of ChatGPT. We could of course implement these ourselves, but there is nothing wrong with getting help and speeding up the process. As far as you know what you are asking for and you can verify the code works as intended, ChatGPT only speeds up our development times. Also, it is very fun to work with.&lt;/p&gt;

&lt;p&gt;Now we have all the pieces in our hand, we can just glue them together! Github repository with final project and ChatGPT conversations: &lt;a href="https://github.com/nooptoday/chatgpt-scalable-websockets" rel="noopener noreferrer"&gt;https://github.com/nooptoday/chatgpt-scalable-websockets&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;You can clone the repository and test it for yourself! Here is a terminal output from running instances:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node1              | [node1] - [client_size] -&amp;gt; [1884]
node2              | [node2] - [client_size] -&amp;gt; [2237]
node3              | [node3] - [client_size] -&amp;gt; [1879]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;6000 connections are sent to node1 initially, and clients are redirected to other nodes. In an ideal world, we would expect to see something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node1              | [node1] - [client_size] -&amp;gt; [2000]
node2              | [node2] - [client_size] -&amp;gt; [2000]
node3              | [node3] - [client_size] -&amp;gt; [2000]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can play with number of virtual nodes, which hash function to use or which parameter from client to hash and see how the results change.&lt;/p&gt;

&lt;p&gt;If you have any questions about the implementation details you can ask here in the comments or create an issue in the GitHub repository. If you are asking, why there is a need for implementing such a solution, you can read previous post that led to this implementation: &lt;a href="https://nooptoday.com/why-websockets-are-hard-to-scale/" rel="noopener noreferrer"&gt;Why Websockets are Hard to Scale&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is it for this post, I hope you enjoyed and learned something new, let me know what you think in the comments!&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>architecture</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How to Trace Websocket Events in NestJS - [Case Study]</title>
      <dc:creator>mkadirtan</dc:creator>
      <pubDate>Mon, 02 Jan 2023 05:45:00 +0000</pubDate>
      <link>https://dev.to/nooptoday/how-to-trace-websocket-events-in-nestjs-case-study-5hi7</link>
      <guid>https://dev.to/nooptoday/how-to-trace-websocket-events-in-nestjs-case-study-5hi7</guid>
      <description>&lt;p&gt;Cover Photo by &lt;a href="https://unsplash.com/@limpido?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Enrico Mantegazza&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In NestJS, HTTP requests are traced by &lt;code&gt;req.id&lt;/code&gt; parameter. You can write your custom id generator, or use default id generated by NestJS or Express or Fastify. However, there is no such concept of request id, or request tracing when it comes to Websockets / Socket.IO.&lt;/p&gt;

&lt;p&gt;Though NestJS allows use of interceptors, filters or guards in &lt;code&gt;Gateways&lt;/code&gt;, one feature I've felt missing is request id. Without request id, you can't trace websocket events and that is not very good for observability.&lt;/p&gt;

&lt;p&gt;In this post, I will explain how to trace websocket events in NestJS. For this, we will create a custom &lt;code&gt;WebSocketAdapter&lt;/code&gt;. In doing so, we will dive deep into source code of NestJS and solve some challenges!&lt;/p&gt;




&lt;h3&gt;
  
  
  What is a WebSocketAdapter?
&lt;/h3&gt;

&lt;p&gt;NestJS makes use of &lt;a href="https://refactoring.guru/design-patterns/adapter" rel="noopener noreferrer"&gt;Adapter Pattern&lt;/a&gt; to abstract underlying libraries from your code. For example NestJS doesn't care if you are using Fastify or Express as an HTTP library. If you want to use another library, you just need to implement an adapter defined by NestJS.&lt;/p&gt;

&lt;p&gt;There are various websocket libraries in Node.js, and also there is Socket.IO, which makes things easier for developers. In this post, we will modify &lt;code&gt;IoAdapter&lt;/code&gt;, from the existing official NestJS package: &lt;a href="https://www.npmjs.com/package/@nestjs/platform-socket.io" rel="noopener noreferrer"&gt;@nestjs/platform-socket.io&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Socket.IO is a bidirectional communication protocol, than can work over HTTP or Websockets. We will use it as an example websocket library in this post, but actual details of the Socket.IO protocol is out of scope for this post. I'm planning to publish an article about how Socket.IO works, if you don't want to miss out, subscribe to &lt;a href="http://nooptoday.com/" rel="noopener noreferrer"&gt;Noop Today&lt;/a&gt;!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How to Write a WebSocketAdapter in NestJS
&lt;/h2&gt;

&lt;p&gt;To create a custom &lt;code&gt;WebSocketAdapter&lt;/code&gt; in NestJS, you need to implement &lt;code&gt;WebSocketAdapter&lt;/code&gt; interface from &lt;a href="https://www.npmjs.com/package/@nestjs/common" rel="noopener noreferrer"&gt;@nestjs/common&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// https://github.com/nestjs/nest/blob/master/packages/common/interfaces/websockets/web-socket-adapter.interface.ts&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;WebSocketAdapter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TServer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;TOptions&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;TServer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;bindClientConnect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TServer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;bindClientDisconnect&lt;/span&gt;&lt;span class="p"&gt;?(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;bindMessageHandlers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WsMessageHandler&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TServer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a typical Node.js application involving websockets / socket.io, you probably have the same functionality in a different way. Since we are using NestJS as our framework, lets see how we should structure our code.&lt;/p&gt;

&lt;p&gt;A typical socket.io server in Node.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Server&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;socket.io&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// create in WebSocketAdapter&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;io&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// bindClientConnect in WebSocketAdapter&lt;/span&gt;
&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;handleConnection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// bindClientDisconnect in WebSocketAdapter&lt;/span&gt;
  &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;disconnect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;handleDisconnect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="c1"&gt;// bindMessageHandlers in WebSocketAdapter&lt;/span&gt;
  &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;handleFoo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OK&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;listening on *:3000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// close in WebSocketAdapter&lt;/span&gt;
&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NestJS provides an &lt;code&gt;AbstractWsAdapter&lt;/code&gt; class to make things easier for us. So instead of this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WebSocketAdapter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyWebSocketAdapter&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;WebSocketAdapter&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AbstractWsAdapter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/websockets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyWebsocketAdapter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractWsAdapter&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference is that, &lt;code&gt;AbstractWsAdapter&lt;/code&gt; provides default implementations for some methods, but you still need to implement &lt;code&gt;create&lt;/code&gt; and &lt;code&gt;bindMessageHandlers&lt;/code&gt; methods.&lt;/p&gt;

&lt;p&gt;We will act smart and use existing code from the official package, and make modifications only in required parts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Existing IoAdapter from @nestjs/platform-socket.io
&lt;/h3&gt;

&lt;p&gt;This is the &lt;code&gt;IoAdapter&lt;/code&gt; from NestJS official packages, that acts as a bridge between NestJS and Socket.IO.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// https://github.com/nestjs/nest/blob/master/packages/platform-socket.io/adapters/io-adapter.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isFunction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isNil&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common/utils/shared.utils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;AbstractWsAdapter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;MessageMappingProperties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/websockets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DISCONNECT_EVENT&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/websockets/constants&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fromEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mergeMap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;share&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;takeUntil&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs/operators&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ServerOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Socket&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;socket.io&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IoAdapter&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractWsAdapter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ServerOptions&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;server&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createIOServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;opt&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;isFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;namespace&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createIOServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createIOServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;createIOServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpServer&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;httpServer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;bindMessageHandlers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MessageMappingProperties&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="nx"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;disconnect$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fromEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DISCONNECT_EVENT&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;share&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;source$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fromEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;mergeMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mapPayload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isNil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
          &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="nf"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;disconnect$&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;source$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nf"&gt;isFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;mapPayload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nb"&gt;Function&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;Function&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isAck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;isFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isAck&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lastElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see what does all the methods do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;create&lt;/code&gt; method is responsible for creating the socket.io server, we don't need to modify here.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;createIoServer&lt;/code&gt; is an helper method for &lt;code&gt;create&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bindMessageHandlers&lt;/code&gt; is responsible for delivering socket.io messages to our handlers. We will modify this for sending extra arguments to our handlers.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mapPayload&lt;/code&gt; parses payload from socket.io to &lt;code&gt;{ ack, data }&lt;/code&gt;, we don't need to modify here.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, we just need to focus on &lt;code&gt;bindMessageHandlers&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modifying The bindMessageHandlers
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;bindMessageHandlers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MessageMappingProperties&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="nx"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;disconnect$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fromEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DISCONNECT_EVENT&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;share&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;source$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fromEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;mergeMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mapPayload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isNil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
          &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="nf"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;disconnect$&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;source$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nf"&gt;isFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, lets understand what is &lt;code&gt;handlers&lt;/code&gt; in this. It has the type: &lt;code&gt;MessageMappingProperties&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;MessageMappingProperties&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;methodName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In socket.io terms: &lt;code&gt;socket.on(message, callback)&lt;/code&gt;, &lt;em&gt;message&lt;/em&gt; will match the event name, and &lt;em&gt;callback&lt;/em&gt; will be the actual handler function.&lt;/p&gt;

&lt;p&gt;So, in order to pass parameters to our handler methods, we must pass parameters to the &lt;code&gt;**callback**&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Lets take a closer look at code with additional commentary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// message --&amp;gt; eventName&lt;/span&gt;
&lt;span class="c1"&gt;// callback --&amp;gt; eventHandler&lt;/span&gt;
&lt;span class="nx"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// RxJS equivelant for --&amp;gt; socket.on(message)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;source$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fromEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="c1"&gt;// payload is socket.io payload&lt;/span&gt;
        &lt;span class="nf"&gt;mergeMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mapPayload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="c1"&gt;// transform, transforms our callback handler to observable&lt;/span&gt;
            &lt;span class="c1"&gt;// callback function is called with TWO parameters&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isNil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
                &lt;span class="c1"&gt;// If callback returns any response, wrap it with ack&lt;/span&gt;
                &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="nf"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;disconnect$&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;source$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// If you return { event: 'foo', data: 'bar' } from handler&lt;/span&gt;
        &lt;span class="c1"&gt;// See: https://docs.nestjs.com/websockets/gateways#multiple-responses&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// If client accepts response, send response&lt;/span&gt;
        &lt;span class="nf"&gt;isFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  A Little Problem in NestJS
&lt;/h3&gt;

&lt;p&gt;If you've ever used IoAdapter in your project, you might realize even though the adapter passes two arguments to the callback function, your handler methods don't receive them in full. Let me explain:&lt;/p&gt;

&lt;p&gt;Say you have a message handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MySocketGateway&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;SubscribeMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;fooHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;argument1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;argument2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;argument3&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="nx"&gt;argument1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Client&lt;/span&gt;
      &lt;span class="nx"&gt;argument2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Body&lt;/span&gt;
      &lt;span class="nx"&gt;argument3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// undefined&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you go ahead and try something like this, you will see that 1st argument is Socket / Client object, 2nd argument is body BUT 3rd argument is undefined. Two questions come to mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where did 1st argument came from?&lt;/li&gt;
&lt;li&gt;Where did my ack function disappear?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lets go with the first question, if we dive deep into underlying NestJS code, we can find the exact place where &lt;code&gt;adapter.bindMessageHandlers&lt;/code&gt; is called.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// https://github.com/nestjs/nest/blob/21bd8c37364a2a2591e3de9bfb88d32d09431438/packages/websockets/web-sockets-controller.ts#L147&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;subscribeMessages&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;subscribersMap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MessageMappingProperties&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NestGateway&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;adapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getIoAdapter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handlers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;subscribersMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}));&lt;/span&gt;
    &lt;span class="nx"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bindMessageHandlers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nf"&gt;fromPromise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pickResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mergeAll&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you look closely, callback is bound with two parameters. &lt;code&gt;bind&lt;/code&gt; method has one required argument for &lt;code&gt;this&lt;/code&gt;, and rest of the arguments are supplied as arguments to the function - *callback. *More info about this in &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind" rel="noopener noreferrer"&gt;mozilla docs&lt;/a&gt;. So, our 1st argument is fixed by NestJS to be client object.&lt;/p&gt;

&lt;h4&gt;
  
  
  How about ack function, why does it disapper?
&lt;/h4&gt;

&lt;p&gt;This was very hard for me to debug but I've found why does that happen, and how you can fix it!&lt;/p&gt;

&lt;p&gt;The problem is not about the ack function. I've tried sending different parameters, or sending more than two parameters to callback function but only the first parameter ends up in handler, and rest is gone.&lt;/p&gt;

&lt;p&gt;There is a helper class &lt;code&gt;[WsContextCreator](https://github.com/nestjs/nest/blob/aa3ad07c1023b71edda6b6ea53374787d3712231/packages/websockets/context/ws-context-creator.ts#L56)&lt;/code&gt; in &lt;code&gt;@nestjs/websockets&lt;/code&gt;, that is responsible for attaching &lt;code&gt;Interceptors&lt;/code&gt;, &lt;code&gt;Guards&lt;/code&gt;, &lt;code&gt;Pipes&lt;/code&gt; and &lt;code&gt;ExceptionHandlers&lt;/code&gt; to handlers, &lt;strong&gt;AND managing parameters sent to handler methods!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That helper class is responsible for disappearing parameters! The reason it makes other parameters disappear is related to this use case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyWebsocketGateway&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;SubscribeMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;handleFoo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;SubscribeMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;handleBar&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;MessageBody&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to decorate your handler parameters with &lt;code&gt;@MessageBody&lt;/code&gt; or &lt;code&gt;@ConnectedSocket&lt;/code&gt;, the &lt;code&gt;WsContextCreator&lt;/code&gt; assigns those parameters for you. You can even do experiments like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyWebsocketGateway&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;SubscribeMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;handleFoo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;arg2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;arg3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;MessageBody&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;arg2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;arg3&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;// All undefined&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I won't go into line by line details of how does this happen, but I will provide you a conceptual explanation and if you want to investigate more, you can always look at source code of @nestjs/websockets for a good exercise.&lt;/p&gt;

&lt;p&gt;The key point is &lt;code&gt;WsContextCreator&lt;/code&gt; extracts data from initial arguments to the callback function, rearranges them and sends those arguments to your handler function. During the extraction process, &lt;code&gt;WsContextCreator&lt;/code&gt; looks up metadata of the handler function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// https://github.com/nestjs/nest/blob/aa3ad07c1023b71edda6b6ea53374787d3712231/packages/websockets/context/ws-context-creator.ts#L163&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contextUtils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reflectCallbackMetadata&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TMetadata&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;methodName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;PARAM_ARGS_METADATA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_CALLBACK_METADATA&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your function doesn't have &lt;code&gt;PARAM_ARGS_METADATA&lt;/code&gt;, NestJS assigns default callback metadata. Guess what, &lt;code&gt;DEFAULT_CALLBACK_METADATA&lt;/code&gt; assigns only two parameters to our handler parameters - &lt;em&gt;client and payload.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// https://github.com/nestjs/nest/blob/master/packages/websockets/context/ws-metadata-constants.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WsParamtype&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../enums/ws-paramtype.enum&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_CALLBACK_METADATA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;WsParamtype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PAYLOAD&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:1`&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pipes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;WsParamtype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SOCKET&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:0`&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pipes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Solution for Providing Additional Parameters to Handlers
&lt;/h3&gt;

&lt;p&gt;NestJS exports an undocumented helper function called &lt;code&gt;assignCustomParameterMetadata&lt;/code&gt;, which allows us to override &lt;code&gt;DEFAULT_CALLBACK_METADATA&lt;/code&gt; and use our own metadata.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// https://github.com/nestjs/nest/blob/5aeb40b/packages/common/utils/assign-custom-metadata.util.ts#L9&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;assignCustomParameterMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RouteParamMetadata&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;paramtype&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CustomParamFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ParamData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;pipes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PipeTransform&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;PipeTransform&lt;/span&gt;&lt;span class="p"&gt;)[]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;paramtype&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;CUSTOM_ROUTE_AGRS_METADATA&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;pipes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function is not self-explanatory, but I think it will be much more clear after example below. Important thing is "where should we use this function?".&lt;/p&gt;

&lt;p&gt;This function is meant to modify &lt;code&gt;PARAM_ARGS_METADATA&lt;/code&gt;, and normally that metadata is defined by decorators such as &lt;code&gt;@ConnectedSocket&lt;/code&gt; or &lt;code&gt;@MessageBody&lt;/code&gt;. So, lets comply with the conventions and create ourselves a new parameter decorator: &lt;code&gt;@Ack&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the &lt;a class="mentioned-user" href="https://dev.to/ack"&gt;@ack&lt;/a&gt; Decorator
&lt;/h3&gt;

&lt;p&gt;If you are not familiar with the concept of decorators, or decorators in NestJS, you can read my previous article: &lt;a href="http://nooptoday.com/custom-decorators-in-nestjs/" rel="noopener noreferrer"&gt;Using Custom Decorators in NestJS&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PARAM_ARGS_METADATA&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/websockets/constants&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Ack&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;ParameterDecorator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// index is the index of parameter we decorated&lt;/span&gt;
&lt;span class="c1"&gt;// It is not related to getArgByIndex below!&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Get existing metadata of the handler&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Reflect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PARAM_ARGS_METADATA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
        &lt;span class="c1"&gt;// Extend with new metadata&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;assignCustomParameterMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExecutionContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// This allows NestJS to extract required parameter from initial arguments supplied to 'callback' function&lt;/span&gt;
            &lt;span class="c1"&gt;// Index here needs to match index of the callback parameters&lt;/span&gt;
            &lt;span class="c1"&gt;// 0 --&amp;gt; Client&lt;/span&gt;
            &lt;span class="c1"&gt;// 1 --&amp;gt; Payload from IoAdapter&lt;/span&gt;
            &lt;span class="c1"&gt;// 2 --&amp;gt; Ack from IoAdapter&lt;/span&gt;
            &lt;span class="c1"&gt;// 0 is always client, but rest of the parameters depend on the underlying adapter.&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getArgByIndex&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nb"&gt;Reflect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PARAM_ARGS_METADATA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can reach our &lt;code&gt;ack&lt;/code&gt; function from the handler as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyWebSocketGateway&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;SubscribeMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;fooHandler&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;MessageBody&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Ack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nf"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo_response&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Lets Move On With RequestId
&lt;/h3&gt;

&lt;p&gt;That really was a case study, isn't it? Lets add a request id to our handler parameters in case we want to trace our requests.&lt;/p&gt;

&lt;p&gt;First we need to modify our adapter, if you remember from above, the adapter supplies arguments to the callback function. We can create a request id in our adapter and supply it to the callback.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// You can make your own implementation for this.&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;createRequestId&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomUUID&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;bindMessageHandlers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MessageMappingProperties&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="nx"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;disconnect$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fromEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DISCONNECT_EVENT&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nf"&gt;share&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;handlers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;source$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fromEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;mergeMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mapPayload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="c1"&gt;// &amp;lt;-- Modified Section Start&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRequestId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestId&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="c1"&gt;// Modified Section End --&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isNil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
          &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="nf"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;disconnect$&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;source$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nf"&gt;isFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is all the modification our adapter needs. Now we can create another decorator: &lt;code&gt;@RequestId&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PARAM_ARGS_METADATA&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/websockets/constants&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RequestId&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;ParameterDecorator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Reflect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PARAM_ARGS_METADATA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;assignCustomParameterMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RequestId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExecutionContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getArgByIndex&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nb"&gt;Reflect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PARAM_ARGS_METADATA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is exactly the same decorator with &lt;code&gt;@Ack&lt;/code&gt; with only difference being &lt;code&gt;return input.getArgByIndex(3);&lt;/code&gt;. Now our handler function looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyWebSocketGateway&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;SubscribeMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;fooHandler&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;MessageBody&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Ack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;RequestId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;requestId&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Received request with id: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;ack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo_response&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Next Steps
&lt;/h3&gt;

&lt;p&gt;If you don't want to deal with all of these, I'm currently working on an npm package that has better developer ergonomics compared to official @nestjs/platform-socket.io package. I'm aware that decorating every parameter in handler functions can be ugly and tiring to eyes. I believe there are more beautiful solutions to this problem. I'm trying to figure out which solution would result in better developer experience.&lt;/p&gt;

&lt;p&gt;I would like to hear your opinions about this. Whether you suggest a usage example, or you face other problems with official package, please let me know what you think in the comments.&lt;/p&gt;

&lt;p&gt;Also, if you don't want to miss out on articles about NestJS and programming in general subscribe to &lt;a href="http://nooptoday.com/" rel="noopener noreferrer"&gt;Noop Today&lt;/a&gt;. I hope you learned something new today, see you in the upcoming posts!&lt;/p&gt;




&lt;p&gt;Here is the repo that contains &lt;code&gt;TraceableIoAdapter&lt;/code&gt; with example code: &lt;a href="https://github.com/nooptoday/nestjs-trace-websocket-events" rel="noopener noreferrer"&gt;https://github.com/nooptoday/nestjs-trace-websocket-events&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>gratitude</category>
    </item>
    <item>
      <title>Why Websockets are Hard To Scale?</title>
      <dc:creator>mkadirtan</dc:creator>
      <pubDate>Thu, 22 Dec 2022 06:02:34 +0000</pubDate>
      <link>https://dev.to/nooptoday/why-websockets-are-hard-to-scale-1267</link>
      <guid>https://dev.to/nooptoday/why-websockets-are-hard-to-scale-1267</guid>
      <description>&lt;p&gt;Cover photo by &lt;a href="https://unsplash.com/@fabioha" rel="noopener noreferrer"&gt;fabio&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EDIT: Second part of the series is released&lt;/strong&gt; &lt;a href="https://dev.to/nooptoday/scalable-websocket-server-implemented-by-chatgpt-15p1"&gt;Scalable Websocket Server Implemented by ChatGPT&lt;/a&gt; Check it out, it has a fully working scalable websocket server repository!&lt;/p&gt;

&lt;p&gt;Websockets provide an important feature: bidirectional communication. Which allows servers to &lt;strong&gt;push&lt;/strong&gt; events to clients, without the need of a client request.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;bidirectional&lt;/strong&gt; nature of websockets is both a grace and a curse! Even though it provides a great ton of use case for websockets, it makes implementing a scalable websocket server a lot harder compared to HTTP servers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Shameless self promotion:&lt;/em&gt; I think websockets are an important part of the web, and they need more recognition among software development world. I am planning to publish more posts about the websockets, if you don't want to miss out you can check out &lt;a href="https://nooptoday.com/" rel="noopener noreferrer"&gt;https://nooptoday.com/&lt;/a&gt; and subscribe to my mailing list!&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What Makes Websockets Unique?
&lt;/h2&gt;

&lt;p&gt;Websocket is an application layer protocol, just like HTTP which is another application layer protocol. Both protocols are implemented over TCP connection. But they have different characteristics and they represent two different countries in the communications world - *if that makes sense :) *&lt;/p&gt;

&lt;p&gt;HTTP carries the flag for request-response based communication model,  and Websocket carries the flag for bidirectional communication model.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Side Note: In an attempt to draw a clearer picture of Websocket, you will see a HTTP vs Websocket comparison throughout the post. But that doesn't mean they are competing protocols, instead they both have their use cases.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Characteristics of Websocket:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bidirectional communication&lt;/li&gt;
&lt;li&gt;Long lived TCP connection&lt;/li&gt;
&lt;li&gt;Stateful protocol&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Characteristics of HTTP:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Request response based communication&lt;/li&gt;
&lt;li&gt;Short lived TCP connection&lt;/li&gt;
&lt;li&gt;Stateless protocol&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Stateful vs. Stateless Protocols
&lt;/h3&gt;

&lt;p&gt;I'm sure you've seen some of the posts about creating &lt;em&gt;stateless, and endlessly scalable backend servers.&lt;/em&gt; They tell you to use JWT tokens for stateless authentication, and use lambda functions in your stateless application etc.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is this &lt;strong&gt;state&lt;/strong&gt; they are talking about and why it is so important when it comes to scaling server applications?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;State&lt;/strong&gt; is all the information your application has to &lt;em&gt;remember&lt;/em&gt; to function correctly. For example, your application should remember logged in users. 99% of the applications do this ( &lt;em&gt;source: trust me&lt;/em&gt; ), and it is called session management.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Okay, then state is a great thing! Why do people hate it, and always try to make &lt;strong&gt;stateless applications?&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You need to store your state in somewhere, and that &lt;em&gt;somewhere&lt;/em&gt; is typically the memory of server. But memory of your application server is not reachable from other servers, and the problem begins. &lt;/p&gt;

&lt;p&gt;Imagine a scenario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User A&lt;/strong&gt; makes a request to &lt;strong&gt;Server 1&lt;/strong&gt;. &lt;strong&gt;Server 1&lt;/strong&gt; authenticates &lt;strong&gt;User A&lt;/strong&gt;, and saves its &lt;strong&gt;Session A&lt;/strong&gt;, to the memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User A&lt;/strong&gt; makes second request to &lt;strong&gt;Server 2&lt;/strong&gt;. &lt;strong&gt;Server 2&lt;/strong&gt; searches saved sessions but it can't find &lt;strong&gt;Session A&lt;/strong&gt;, because it is stored inside &lt;strong&gt;Server 1&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order for your server to become scalable you need to manage the state outside of your application. For example you can save sessions to a Redis instance. This makes application state available to all the servers via Redis, and &lt;strong&gt;Server 2&lt;/strong&gt; can read &lt;strong&gt;Session A&lt;/strong&gt; from the Redis.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Stateful Websocket:&lt;/strong&gt; Opening a Websocket connection is like a wedding between the client and the server: the connection stays open until one of the parties close it ( &lt;em&gt;or cheat on it, due to network conditions of course&lt;/em&gt; ).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stateless HTTP:&lt;/strong&gt; On the other hand, HTTP is a heartbreaker, it wants to end everything as fast as possible. Once a HTTP connection is opened, client sends a request and as soon as server responds, the connection is closed.&lt;/p&gt;

&lt;p&gt;Okay, I will stop with the jokes now, but remember Websocket connections are &lt;em&gt;typically&lt;/em&gt; long lived, whereas HTTP connections are meant to end asap. The moment you introduce Websockets into your application, it becomes &lt;strong&gt;stateful.&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  In Case You Wonder
&lt;/h4&gt;

&lt;p&gt;Even though both HTTP and Websocket are built on top of TCP, one can be stateles, while the other one is stateful. For simplicity, I didn't want to confuse you with details about TCP. But keep in mind, even in HTTP, underlying TCP connection can be long lived. This is out of scope for this post, but you can learn more about it &lt;a href="https://en.wikipedia.org/wiki/HTTP_persistent_connection" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Can't I Just Use a Redis Instance to Store Sockets?
&lt;/h3&gt;

&lt;p&gt;In the previous example with sessions, the solution was simple. Use an external service to store sessions, so every other server can read sessions from there ( Redis Instance ).&lt;/p&gt;

&lt;p&gt;Websockets are a different case, because your state is not only the data about socket, inevitably you are storing &lt;strong&gt;connections&lt;/strong&gt; in your server. Every websocket connection is bound to a single server, and there is no way for other servers to send data to that connection.&lt;/p&gt;

&lt;p&gt;Now, comes the second problem, you must have a way for other servers to send message to that websocket connection. For that, you need to have a way to send messages between servers. Luckily, that is already a thing called &lt;strong&gt;message broker&lt;/strong&gt;. You can even use Redis pub / sub mechanism to send messages between your servers.&lt;/p&gt;

&lt;p&gt;Let's summarize what have we discussed so far:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Websocket connections are stateful&lt;/li&gt;
&lt;li&gt;A websocket server automatically becomes a stateful application&lt;/li&gt;
&lt;li&gt;In order for stateful applications to scale, you need to have an external state storage ( example: Redis )&lt;/li&gt;
&lt;li&gt;Websocket connections are bound to a single server&lt;/li&gt;
&lt;li&gt;Servers need to connect to a message broker to send message to websockets in other servers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Is that it? Adding a Redis instance to my stack solves all the scaling problems with Websockets?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, no. Well, there is another issue with scalable websocket architectures: &lt;strong&gt;Load Balancing&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Load Balancing Websockets
&lt;/h3&gt;

&lt;p&gt;Load balancing is a technique to ensure, all of your servers share somewhat equal amount of load. In a plain HTTP server, this can be implemented with simple algorithms like Round Robin. But that is not ideal for a Websocket server.&lt;/p&gt;

&lt;p&gt;Imagine you have an auto scaling server group. That means, as the load increases new instances are deployed and as the load decreases some instances are closed.&lt;/p&gt;

&lt;p&gt;Since HTTP requests are short lived, the load balances somewhat evenly across all instances even though servers are added / removed.&lt;/p&gt;

&lt;p&gt;Websocket connections are long lived ( persistent ), which means new servers will not take the load off from old servers. Because, old servers are still persisting their websocket connections. As an example, say &lt;strong&gt;Server 1&lt;/strong&gt;, has 1000 open websocket connections. Ideally, when a new server &lt;strong&gt;Server 2&lt;/strong&gt; is added, you want to move 500 websocket connections from &lt;strong&gt;Server 1&lt;/strong&gt;, to &lt;strong&gt;Server 2&lt;/strong&gt;. But that is not possible with traditional load balancers.&lt;/p&gt;

&lt;p&gt;You can drop all websocket connections, and expect clients to reconnect. Then you can have 500 / 500 websocket connection distribution on your servers, but that is a bad solution because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Servers will be bombarded with reconnection requests, and server load will fluctuate greatly&lt;/li&gt;
&lt;li&gt;If servers are scaled frequently, clients will reconnect frequently and it can have a negative effect on user experience&lt;/li&gt;
&lt;li&gt;It is not an elegant solution - &lt;em&gt;I know you guys care about this!&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The most elegant solution for this problem is called: &lt;strong&gt;Consistent Hashing&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Load Balancing Algorithm: Consistent Hashing
&lt;/h2&gt;

&lt;p&gt;There are various load balancing algorithms out there, but consistent hashing is just from another world.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnooptoday.com%2Fcontent%2Fimages%2F2022%2F12%2Fimage-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnooptoday.com%2Fcontent%2Fimages%2F2022%2F12%2Fimage-1.png" alt="meme about consistent hashing"&gt;&lt;/a&gt;&lt;br&gt;
The basic idea behind load balancing with consistent hashing is that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hash the incoming connection with some property, lets say &lt;strong&gt;userId =&amp;gt; hashValue&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;You can then use &lt;strong&gt;hashValue&lt;/strong&gt; to determine which server this user should connect to&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This assumes that your hash function evenly distributes &lt;strong&gt;userId&lt;/strong&gt; to &lt;strong&gt;hashValue&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;BUT, there is always a but, isn't there... Now you still have the problem when you add / remove servers. And the solution is to drop connections when new servers are added or removed.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Wait, what! You just said that was a bad idea? How is that a solution, now?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The beauty of this solution is that, with consistent hashing you don't have to drop &lt;em&gt;all the connections&lt;/em&gt;, but you should just drop only some of the connections. Actually, you drop exactly how many connections you need to drop. Let me explain with a scenario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initially, &lt;strong&gt;Server 1&lt;/strong&gt; has 1000 connections&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server 2&lt;/strong&gt; is added&lt;/li&gt;
&lt;li&gt;As soon as &lt;strong&gt;Server 2&lt;/strong&gt; is added, &lt;strong&gt;Server 1&lt;/strong&gt; runs a rebalancing algorithm&lt;/li&gt;
&lt;li&gt;Rebalance algorithm detects which websocket connections are needed to drop, and if our hash function detects roughly 500 connections that need to go to &lt;strong&gt;Server 2&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server 1&lt;/strong&gt;, emits a reconnect message to those 500 clients, and they connect to &lt;strong&gt;Server 2&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=UF9Iqmg94tk" rel="noopener noreferrer"&gt;Here is a great video by ByteByteGo&lt;/a&gt; that explains the concept visually.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Much Simpler And Efficient Solution
&lt;/h3&gt;

&lt;p&gt;Discord manages a lot of Websocket connections. How did they solve the problem with load balancing?&lt;/p&gt;

&lt;p&gt;If you investigate the &lt;a href="https://discord.com/developers/docs/topics/gateway#get-gateway" rel="noopener noreferrer"&gt;developer docs&lt;/a&gt; about how to establish a websocket connection, here is how they do it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Send a HTTP GET request to &lt;code&gt;/gateway&lt;/code&gt; endpoint, receive available Websocket server urls.&lt;/li&gt;
&lt;li&gt;Connect to Websocket server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The magic behind this solution is, you can control which server new clients should connect. If you add new server, you can direct all the new connections to new server. If you want to move 500 connections from &lt;strong&gt;Server 1&lt;/strong&gt; to &lt;strong&gt;Server 2&lt;/strong&gt;, simply drop 500 connections from &lt;strong&gt;Server 1&lt;/strong&gt;, and supply &lt;strong&gt;Server 2&lt;/strong&gt; address from &lt;code&gt;/gateway&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/gateway&lt;/code&gt; endpoint needs to know load distributions of all the servers, and make decisions based on that. It can simply return url of the server with minimum load. &lt;/p&gt;

&lt;p&gt;This solution works and much simpler compared to consistent hashing. But, consistent hashing method doesn't need to know about load distribution of all the servers, and it doesn't require a HTTP request before hand. Therefore, clients can connect faster but that is generally not an important consideration. Also, implementing a consistent hashing algorithm can be tricky. That is why, I am planning to create a follow up post about Implementing Consistent Hashing for Load Balancing Websockets.&lt;/p&gt;

&lt;p&gt;I hope you learned something new from this post, please let me know what you think in the comments. You can subscribe to mailing list if you don't want to miss out on new posts!&lt;/p&gt;

</description>
      <category>websocket</category>
      <category>scalable</category>
      <category>stateful</category>
      <category>backend</category>
    </item>
    <item>
      <title>Best Way to Create Dynamic Modules in NestJS</title>
      <dc:creator>mkadirtan</dc:creator>
      <pubDate>Wed, 14 Dec 2022 07:00:00 +0000</pubDate>
      <link>https://dev.to/nooptoday/best-way-to-create-dynamic-modules-in-nestjs-5003</link>
      <guid>https://dev.to/nooptoday/best-way-to-create-dynamic-modules-in-nestjs-5003</guid>
      <description>&lt;p&gt;Creating dynamic modules in NestJS can be complex. Use this method and you will never be afraid of creating dynamic modules again!&lt;/p&gt;

&lt;p&gt;Cover Photo by &lt;a href="https://unsplash.com/@westwindairservice?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Westwind Air Service&lt;/a&gt; on &lt;a href="https://unsplash.com/@westwindairservice?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;NestJS module system is very helpful. They allow us to organize our code, and they help us define module boundaries. Within &lt;code&gt;@Module&lt;/code&gt; you can define everything about your module. From the NestJS docs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Global&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CatsController&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./cats.controller&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CatsService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./cats.service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CommonModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../common/common.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Global&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CommonModule&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;controllers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CatsController&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CatsService&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CatsService&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CatsModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://docs.nestjs.com/modules#global-modules"&gt;https://docs.nestjs.com/modules#global-modules&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But things get complicated when you want to configure your module dynamically. This is typically required by database modules but there are many other cases that require you to create dynamic module in NestJS.&lt;/p&gt;

&lt;p&gt;As a convention dynamic modules in NestJS have static methods such as &lt;code&gt;forRoot&lt;/code&gt;, &lt;code&gt;forRootAsync&lt;/code&gt;, &lt;code&gt;forFeature&lt;/code&gt; In this post you will learn how to create a dynamic module in NestJS with all the benefits but with least complexity!&lt;/p&gt;




&lt;h3&gt;
  
  
  NestJS Official Docs are Too Complex
&lt;/h3&gt;

&lt;p&gt;Here is a dynamic module example from the docs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Module&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ConfigService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./config.service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ConfigurableModuleClass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ASYNC_OPTIONS_TYPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;OPTIONS_TYPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./config.module-definition&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ConfigService&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ConfigService&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConfigModule&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ConfigurableModuleClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;OPTIONS_TYPE&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;DynamicModule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// your custom logic here&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;registerAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;ASYNC_OPTIONS_TYPE&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;DynamicModule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// your custom logic here&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://docs.nestjs.com/fundamentals/dynamic-modules#extending-auto-generated-methods"&gt;https://docs.nestjs.com/fundamentals/dynamic-modules#extending-auto-generated-methods&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I know I've picked the most bloated example but still, creating a dynamic module as documented in NestJS docs, doesn't look simple. There is a good reason for that. On one hand NestJS tries to provide a simple API for using module system, but on the other hand the API must provide enough access to satisfy custom needs of developers. I think they did a great job at designing their API, but this is the reason examples from official docs are complex.&lt;/p&gt;

&lt;h3&gt;
  
  
  @golevelup Team To The Rescue
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/golevelup/nestjs"&gt;@golevelup&lt;/a&gt; team has some great packages to use along your NestJS project. We will use &lt;code&gt;@golevelup/nestjs-modules&lt;/code&gt; for this post. We will use defaults provided by their package, in exchange our dynamic modules will be much simpler and easier to maintain.&lt;/p&gt;

&lt;p&gt;I assume you've already spin up a NestJS project. We need to install &lt;code&gt;@golevelup/nestjs-modules&lt;/code&gt; package to our project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @golevelup/nestjs-modules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What Will We Build
&lt;/h3&gt;

&lt;p&gt;For the sake of providing a good use case, lets create a serializer module that can use alternative strategies. Create the following files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Inside src folder&lt;/span&gt;
/-&amp;gt; serde
/--&amp;gt; serde.module.ts
/--&amp;gt; serde.service.ts
/--&amp;gt; json.provider.ts
/--&amp;gt; msgpack.provider.ts
/--&amp;gt; constants.ts
/--&amp;gt; interfaces.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how we will continue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a configurable dynamic module &lt;code&gt;SerdeModule&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Inject &lt;code&gt;JsonProvider&lt;/code&gt; and &lt;code&gt;MsgpackProvider&lt;/code&gt; to &lt;code&gt;SerdeService&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Define &lt;code&gt;SerdeModuleOptions&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Expose selected strategy from &lt;code&gt;SerdeService&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Creating Configurable Dynamic Module
&lt;/h2&gt;

&lt;p&gt;Create your module as usual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// serde.module.ts&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SerdeModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add providers to your module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;JsonProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./json.provider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MsgpackProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./msgpack.provider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SerdeService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./serde.service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;JsonProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;MsgpackProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;SerdeService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SerdeModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One last thing, we will expose &lt;code&gt;SerdeModule&lt;/code&gt;'s functionality from &lt;code&gt;SerdeService&lt;/code&gt;. Therefore it needs to be exported:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;JsonProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./json.provider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MsgpackProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./msgpack.provider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SerdeService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./serde.service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;JsonProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;MsgpackProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;SerdeService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;SerdeService&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SerdeModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So far so good, and there is nothing unusual. Now we will make &lt;code&gt;SerdeModule&lt;/code&gt; configurable, specifically we want user to decide which serialization strategy they want to use.&lt;/p&gt;

&lt;p&gt;We need to create an interface to define module options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// interfaces.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;SerdeModuleOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;msgpack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, we will need these options to be accessible within &lt;code&gt;SerdeService&lt;/code&gt;. If you remember from the NestJS docs, module options are injected within providers. And &lt;code&gt;@Inject&lt;/code&gt; decorator provides values via an &lt;code&gt;InjectionToken&lt;/code&gt;. Injection Token acts like a unique id of the value you want to access. It is defined as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;InjectionToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;symbol&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Function&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;new &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Type&lt;/code&gt; is basically a class reference. Since we defined our module options as an interface, we will define a string as Injection Token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// constants.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SERDE_MODULE_OPTIONS_TOKEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SERDE_MODULE_OPTIONS_TOKEN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally we can bring them all together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;JsonProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./json.provider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MsgpackProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./msgpack.provider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SerdeService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./serde.service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createConfigurableDynamicRootModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@golevelup/nestjs-modules&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SERDE_MODULE_OPTIONS_TOKEN&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./constants&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SerdeModuleOptions&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./interfaces&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;JsonProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;MsgpackProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;SerdeService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;SerdeService&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SerdeModule&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;createConfigurableDynamicRootModule&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SerdeModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SerdeModuleOptions&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SERDE_MODULE_OPTIONS_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is all! We've successfully created a dynamic module. Lets put it into use, we can import it within &lt;code&gt;AppModule&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app.module.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SerdeModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./serde.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;SerdeModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SerdeModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice we've never defined a &lt;code&gt;forRoot&lt;/code&gt; method on our class. This method is automatically created by &lt;code&gt;@golevelup/nestjs-modules&lt;/code&gt; and it is type safe, Hurray! There is also the &lt;code&gt;forRootAsync&lt;/code&gt; counterpart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app.module.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SerdeModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./serde.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ConfigModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ConfigService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;SerdeModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forRootAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SerdeModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ConfigModule&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="na"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ConfigService&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="na"&gt;useFactory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;configService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ConfigService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;configService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SERDE_STRATEGY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Accessing Module Options
&lt;/h2&gt;

&lt;p&gt;To make use of provided options, we need to inject it into &lt;code&gt;SerdeService&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SERDE_MODULE_OPTIONS_TOKEN&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./constants&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SerdeModuleOptions&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./interfaces&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SerdeService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SERDE_MODULE_OPTIONS_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;moduleOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SerdeModuleOptions&lt;/span&gt;
    &lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;moduleOptions&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// console output: { moduleOptions: { strategy: 'json' } }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will apply strategy pattern for this example. If you want to learn more about strategy pattern, I recommend you to read &lt;a href="https://betterprogramming.pub/design-patterns-using-the-strategy-pattern-in-javascript-3c12af58fd8a"&gt;https://betterprogramming.pub/design-patterns-using-the-strategy-pattern-in-javascript-3c12af58fd8a&lt;/a&gt; written by Carlos Caballero. Basically we will switch between &lt;code&gt;JsonProvider&lt;/code&gt; and &lt;code&gt;MsgpackProvider&lt;/code&gt; depending on the &lt;code&gt;moduleOptions.strategy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First inject the providers into &lt;code&gt;SerdeService&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SERDE_MODULE_OPTIONS_TOKEN&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./constants&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SerdeModuleOptions&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./interfaces&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;JsonProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./json.provider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MsgpackProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./msgpack.provider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SerdeService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;_strategy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SERDE_MODULE_OPTIONS_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;moduleOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SerdeModuleOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;jsonProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JsonProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;msgpackProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MsgpackProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moduleOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jsonProvider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;msgpack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;msgpackProvider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we can expose our API to outside world:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SERDE_MODULE_OPTIONS_TOKEN&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./constants&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SerdeModuleOptions&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./interfaces&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;JsonProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./json.provider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MsgpackProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./msgpack.provider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SerdeService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;_strategy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SERDE_MODULE_OPTIONS_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;moduleOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SerdeModuleOptions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;jsonProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JsonProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;msgpackProvider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MsgpackProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moduleOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jsonProvider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;msgpack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;msgpackProvider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_strategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_strategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;I leave implementing actual providers to you. If you want to learn more about Strategy Pattern, I am planning to write a detailed post about it. Tell me in the comments if you are interested!&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;We created a dynamic module in NestJS with an example use case. I hope you've learned something new, let me know what you think in the comments!&lt;/p&gt;

</description>
      <category>nestjs</category>
      <category>typescript</category>
      <category>node</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
