<?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: Chiranjib</title>
    <description>The latest articles on DEV Community by Chiranjib (@chiranjib_b).</description>
    <link>https://dev.to/chiranjib_b</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%2F193604%2F47e9f0c9-a996-40bb-9573-6d8f46a9b83b.gif</url>
      <title>DEV Community: Chiranjib</title>
      <link>https://dev.to/chiranjib_b</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chiranjib_b"/>
    <language>en</language>
    <item>
      <title>Platform Engineering for the uninitiated</title>
      <dc:creator>Chiranjib</dc:creator>
      <pubDate>Fri, 29 Aug 2025 07:56:20 +0000</pubDate>
      <link>https://dev.to/chiranjib_b/platform-engineering-for-the-uninitiated-1ifo</link>
      <guid>https://dev.to/chiranjib_b/platform-engineering-for-the-uninitiated-1ifo</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Oh you do platform engineering, you mean CI/CD and pipelines?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This was my friend's response when I told him that I'm a Lead Platform Engineer now! SMH. I don't really blame him though, of late I find myself struggling to answer crisply when people ask me what I do for a living. The easy answer of course is that I am a developer. I have a confession though - I've been in tech for a while, have worked on software development and delivery, but when I started work as a Platform Engineer, it made me feel as if I've been living under a rock!&lt;/p&gt;

&lt;p&gt;I've come across quite a few people who think that &lt;code&gt;DevOps&lt;/code&gt; (and even &lt;code&gt;QA&lt;/code&gt;) is a luxury and not a necessity. Convincing them on the value proposition of having these bedrocks is an uphill battle, but that's not what this article is about. I'm flushing my thoughts in here, with just the intention of spreading awareness and maybe help a person or two if they've been contemplating about this line of work.&lt;/p&gt;

&lt;p&gt;Put simply, a &lt;strong&gt;&lt;em&gt;Platform Engineer&lt;/em&gt;&lt;/strong&gt; creates a &lt;strong&gt;&lt;em&gt;Platform&lt;/em&gt;&lt;/strong&gt;, thereby offering &lt;a href="https://en.wikipedia.org/wiki/Platform_as_a_service" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;Platform as a Service (PaaS)&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;. My first taste of this was about a decade ago, when Cloud technologies were still in the process of being adopted. My team was working on creating tooling for our Operations Team, who were not developers but were solely in charge of managing deployments. The software had a few flavours - Windows or Linux VMs, SQL Server or Oracle PL/SQL databases, multiple application server stacks based on services selected (containers were not yet a widespread thing) and any combination of these could go on AWS or Azure. The Operations team were going crazy trying to manage deployments and upgrades, and our job was to make their jobs easier. We started developing bash and powershell scripts, but then quickly pivoted to developing a webapp instead that would help one deploy any combination of the aforementioned flavours - an Internal Operations Portal, if I may call it that.&lt;/p&gt;

&lt;p&gt;At this point, I expect you to raise a concern - &lt;em&gt;AWS and Azure provide PaaS themselves, why not use it as is?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Well, you would have a valid point; but here's the thing - I've worked with a few programming languages, followed waterfall and agile methodologies, used subversion and git, even tried to understand Jira and came to the conclusion that the most complex of them all is - &lt;em&gt;people!&lt;/em&gt; Teams in charge of an organization's infrastructure and processes are expected to put in the effort to create instructions, knowledge bases, playbooks, et al., but getting people to read and follow them has proven to be a Herculean task - and this is just the beginning of the answer to the &lt;em&gt;why&lt;/em&gt;.&lt;/p&gt;

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

&lt;p&gt;Over time, I've learned that &lt;a href="https://github.com/webpro/programming-principles" rel="noopener noreferrer"&gt;YAGNI is not just a cool sounding word, KISS is not just an act of love, DRY is not just the opposite of wet, and SOLID is not just a state of matter&lt;/a&gt;. Every developer should ideally live by these, and master design patterns that facilitate these. As cloud technologies keep getting more complex and diverse, cross team functions start becoming hazy, and it gets increasingly difficult to achieve consistency and predictability in a software setup. Throw in security to the mix, and conversations quickly shift away from the application related code. This warranted a &lt;em&gt;separation of concern&lt;/em&gt; between software development and software delivery.&lt;/p&gt;

&lt;p&gt;The solution to this problem started with setting up different teams for both - and &lt;code&gt;ClickOps&lt;/code&gt; was coined. As cloud technologies evolved, people realized that it was getting increasingly difficult to keep systems in sync given the room for human error. Naturally, it evolved to the adoption of scripting based pipelines, and it led to the birth of &lt;code&gt;DevOps&lt;/code&gt;. This bridged the gap between development and operations quite a bit, and was based on the idea of &lt;em&gt;you build it, you run it&lt;/em&gt;, which inadvertently caused shrinkage of operations teams. It was progress alright, but still left techies yearning for something more. Application developers were getting overloaded with the cognitive load of managing infrastructure, and it was getting in the way of product development. Besides this, the complexity of application development was shifting from monoliths to microservices. Upholding the need for &lt;em&gt;separation of concern&lt;/em&gt;, technologies evolved and containerization paved the path for taking things to the next level. &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;&lt;em&gt;Docker&lt;/em&gt;&lt;/a&gt; became somewhat ubiquitous and with the advent of containers, came the need for container orchestration. Google looked over their shoulders and donated Borg to the world, which came to be better known as &lt;a href="https://kubernetes.io/" rel="noopener noreferrer"&gt;&lt;em&gt;Kubernetes&lt;/em&gt;&lt;/a&gt; or &lt;em&gt;k8s&lt;/em&gt;. This is where things started to get &lt;em&gt;really&lt;/em&gt; spicy, and the cognitive load on developers quickly started to multiply exponentially.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;DevOps&lt;/code&gt; way had already seen adoption of &lt;a href="https://en.wikipedia.org/wiki/Infrastructure_as_code" rel="noopener noreferrer"&gt;&lt;em&gt;Infrastructure as Code&lt;/em&gt;&lt;/a&gt;, and tools like &lt;a href="https://www.hashicorp.com/en/products/terraform" rel="noopener noreferrer"&gt;&lt;em&gt;Terraform&lt;/em&gt;&lt;/a&gt;, &lt;a href="https://www.chef.io/products/chef-infrastructure-management" rel="noopener noreferrer"&gt;&lt;em&gt;Chef&lt;/em&gt;&lt;/a&gt;, &lt;a href="https://www.pulumi.com/" rel="noopener noreferrer"&gt;&lt;em&gt;Pulumi&lt;/em&gt;&lt;/a&gt;, etc. enabled us to think of our cloud resources as configurations and code. Cloud Engineering needed to evolve along similar lines, and the elephant in the room was - a need for standardization, enter &lt;code&gt;GitOps&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;Some of the brightest minds came together to set up the &lt;a href="https://www.cncf.io/" rel="noopener noreferrer"&gt;&lt;em&gt;Cloud Native Compute Foundation&lt;/em&gt;&lt;/a&gt; and championed the concept of &lt;code&gt;GitOps&lt;/code&gt;. This brought about yet another major shift in developer mindsets, and allowed techies to be more declarative with their infrastructure and focus solely on the &lt;em&gt;what&lt;/em&gt;; the responsibility of &lt;em&gt;how&lt;/em&gt; was abstracted away with the new technologies on the horizon. With Kubernetes widely adopted for container orchestration at scale in the cloud, &lt;a href="https://helm.sh/" rel="noopener noreferrer"&gt;&lt;em&gt;Helm&lt;/em&gt;&lt;/a&gt; surfaced as the package manager for deployments to k8s clusters. The packages came to be known as &lt;code&gt;Charts&lt;/code&gt; and could be deployed with predictability and consistency. This was a step in the right direction, but still included a little bit of &lt;code&gt;ClickOps&lt;/code&gt;. Thanks to CNCF yet again, tools like &lt;a href="https://fluxcd.io/" rel="noopener noreferrer"&gt;&lt;em&gt;Flux&lt;/em&gt;&lt;/a&gt; and &lt;a href="https://argo-cd.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;&lt;em&gt;Argo CD&lt;/em&gt;&lt;/a&gt; alleviated that pain aptly, and it became possible to manage Helm deployments in a declarative manner. As one can tell, this is already a lot to deal with for a developer who's supposed to write code for implementing business logic.&lt;/p&gt;

&lt;p&gt;Software delivery was getting code heavy very quickly - and that is what brought about the need for &lt;em&gt;Platform Engineering&lt;/em&gt;. This was a natural step in the evolution from DevOps, and there are multiple discussions online that &lt;em&gt;DevOps is dead!&lt;/em&gt; I wouldn't quite agree though, but my view is that &lt;em&gt;Platform Engineering&lt;/em&gt; is the wealthy father that adopted the overburdened &lt;em&gt;DevOps&lt;/em&gt; (and it's good friend &lt;em&gt;Site Reliability Engineering&lt;/em&gt;). Let's have a closer look at this new father figure at the horizon, and understand the peculiar mix of skills that is required to be successful:&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Infrastructure Operations&lt;/em&gt;: familiarity with the public cloud  platforms and other IaaS services is a must, which will form the foundation&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Software Development&lt;/em&gt;: there would be requirements to develop services for abstraction, and packages for extending tooling to the application code&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Product Management&lt;/em&gt;: nobody likes to use a bad product, and one must not forget that we are doing this in the first place to make developers' lives easier; we need to strive for the least possible friction and define the &lt;strong&gt;&lt;em&gt;Golden Path&lt;/em&gt;&lt;/strong&gt; for developers and it needs to be well documentated and transparent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the understanding of roles to play, let's try to understand the responsibilities now, I've tried to depict them below:&lt;/p&gt;

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

&lt;p&gt;At the heart of everything, there needs to be security, and the systems in general need to be &lt;a href="https://en.wikipedia.org/wiki/Secure_by_design" rel="noopener noreferrer"&gt;Secure by Design&lt;/a&gt;. Concepts like &lt;a href="https://en.wikipedia.org/wiki/Role-based_access_control" rel="noopener noreferrer"&gt;Role Based Access Control&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Attribute-based_access_control" rel="noopener noreferrer"&gt;Attribute Based Access Control&lt;/a&gt; can not be an afterthought, but need to be baked in from the start. Once artifacts start getting generated at scale, and open source packages keep getting integrated in application code, all the guardrails like License scanning, Static Application Security Testing (SAST), Dynamic Application Security Testing (DAST), and Software Composition Analysis (SCA) need to be in place to stop malicious code in the integration phase. Additional artifacts like SBOM (Software Bill of Materials), test coverage reports and scan reports need to be published for the artifacts being generated during code integration.&lt;/p&gt;

&lt;p&gt;Once all the important tech is in-place to enable software delivery, the necessary augmentation is what comes next. Documentation is a non-negotiable demand of the craft, and tools like &lt;a href="https://plantuml.com/" rel="noopener noreferrer"&gt;PlantUML&lt;/a&gt; and &lt;a href="https://mermaid.js.org/" rel="noopener noreferrer"&gt;Mermaid&lt;/a&gt; have enabled maintenance of Documentation as Code (Docs as Code).&lt;/p&gt;

&lt;p&gt;Smart instrumentation for Site Reliability Engineering is of utmost importance now, because with so many moving parts in a microservices based architecture it is otherwise near impossible to identify problems. Technologies like &lt;a href="https://www.elastic.co/elastic-stack" rel="noopener noreferrer"&gt;ELK&lt;/a&gt; and &lt;a href="https://grafana.com/" rel="noopener noreferrer"&gt;LGTM+&lt;/a&gt; in combination with &lt;a href="https://opentelemetry.io/" rel="noopener noreferrer"&gt;OpenTelemetry&lt;/a&gt; provide respite in that area.&lt;/p&gt;

&lt;p&gt;This is of course not an exhaustive list of what's already existing, and with Agentic applications on the horizon, the scope is only ever going to increase - think &lt;a href="https://owasp.org/www-project-aibom/" rel="noopener noreferrer"&gt;&lt;em&gt;AIBOM&lt;/em&gt;&lt;/a&gt; and AI vulnerability scanners. Other possibilities might also include setting up internal MCP servers to enable small language models that power AI-native applications.&lt;/p&gt;

&lt;p&gt;I'd like to conclude by saying - it's a lot, and it can get very overwhelming very fast, but it's important that we keep calm and resist the urge to boil the ocean on this journey.&lt;/p&gt;

&lt;p&gt;P.S. Before all of this, we must evaluate if the product we're building it for has an actual need for these things at scale. Some food for thought - &lt;br&gt;
&lt;a href="https://world.hey.com/dhh/why-we-re-leaving-the-cloud-654b47e0" rel="noopener noreferrer"&gt;This post by David Heinemeier Hansson&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>devex</category>
      <category>gitops</category>
      <category>platformengineering</category>
    </item>
    <item>
      <title>Beautify WSL2 terminal with ohmyposh</title>
      <dc:creator>Chiranjib</dc:creator>
      <pubDate>Mon, 10 Mar 2025 07:50:25 +0000</pubDate>
      <link>https://dev.to/chiranjib_b/beautify-wsl2-terminal-with-ohmyposh-4igf</link>
      <guid>https://dev.to/chiranjib_b/beautify-wsl2-terminal-with-ohmyposh-4igf</guid>
      <description>&lt;h4&gt;
  
  
  Read on if you
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Are using the combination: Windows, WSL2, Ubuntu&lt;/li&gt;
&lt;li&gt;Don't like the look and feel of the limited terminal&lt;/li&gt;
&lt;li&gt;Like me, aren't yet using Windows Terminal for some inexplicable reason&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Prerequisites
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Have a computer that runs Windows OS (Mine is Windows 10)&lt;/li&gt;
&lt;li&gt;Enable WSL2 -&amp;gt; &lt;a href="https://learn.microsoft.com/en-us/windows/wsl/install" rel="noopener noreferrer"&gt;Here's how, if you need it&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A little tech knowledge about how these things work, just enough to make small changes and understand what's going on&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 1: Installation
&lt;/h4&gt;

&lt;p&gt;Open Ubuntu in WSL and download oh-my-posh. Oh My Posh is a prompt theme engine for your shell (I, being a simpleton, am using bash). Their somewhat &lt;a href="https://ohmyposh.dev/docs/installation/linux" rel="noopener noreferrer"&gt;detailed installation instructions&lt;/a&gt; enable you to download and set it up smoothly.&lt;/p&gt;

&lt;p&gt;Once the installation has completed, let's take small steps towards enabling it. Let's edit the &lt;code&gt;~/.bashrc&lt;/code&gt; file to ensure that it loads when we start.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export PATH=$PATH:~/.local/bin
if [ -f $(which oh-my-posh) ]; then
  eval "$(oh-my-posh init bash)"
fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see what we just did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;assuming that oh-my-posh got installed in the location &lt;code&gt;~/.local/bin&lt;/code&gt;, we are ensuring that it's loaded in the &lt;code&gt;PATH&lt;/code&gt;. This is necessary to be able to invoke the command itself.&lt;/li&gt;
&lt;li&gt;since we are using bash, we invoked the command &lt;code&gt;oh-my-posh init bash&lt;/code&gt; at startup, so that things are nice and pretty for us to use from the start.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 2: Selecting a theme
&lt;/h4&gt;

&lt;p&gt;Discover &lt;a href="https://ohmyposh.dev/docs/themes" rel="noopener noreferrer"&gt;all the ohmyposh themes&lt;/a&gt; that you can choose from, and download the file from the link provided there or just pick one from the list here: &lt;a href="https://github.com/JanDeDobbeleer/oh-my-posh/tree/main/themes" rel="noopener noreferrer"&gt;https://github.com/JanDeDobbeleer/oh-my-posh/tree/main/themes&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's assume we have downloaded the necessary theme &lt;code&gt;.json&lt;/code&gt; files in the directory &lt;code&gt;~/.poshthemes&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's now modify the file &lt;code&gt;~/.bashrc&lt;/code&gt; to pick the theme up as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if [ -f $(which oh-my-posh) ]; then
  eval "$(oh-my-posh init bash --config ~/.poshthemes/jandedobbeleer.omp.json)"
fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: Installing a Nerd Font
&lt;/h4&gt;

&lt;p&gt;Oh My Posh requires a Nerd Font to work. So, explore &lt;a href="https://www.nerdfonts.com/font-downloads" rel="noopener noreferrer"&gt;all the nerd fonts&lt;/a&gt;, have your pick, and download the font to your windows system. Once, the font is downloaded, navigate to the font location, right click, and click &lt;em&gt;Install&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Once installed, verify that the font is visible in the list of fonts: &lt;code&gt;Win + R&lt;/code&gt;, type &lt;em&gt;fonts&lt;/em&gt;. I went with Inconsolata.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnzsivs0jzz8ygni8qen2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnzsivs0jzz8ygni8qen2.png" alt="Verifying the installed font" width="750" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 4: Configure the installed font
&lt;/h4&gt;

&lt;p&gt;As a final step, we need to configure the emulator, that is used by Windows. Launch &lt;em&gt;Command Prompt&lt;/em&gt; or &lt;em&gt;Ubuntu App&lt;/em&gt;, right click on the toolbar, click &lt;em&gt;Properties&lt;/em&gt;. This should allow you to select the installed font. One easy to miss detail is that CMD works with Monospaced fonts only. So, the font that you had chosen, ensure that you've installed the Mono variant.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjs20u1ea7djjb0ix2ve.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjs20u1ea7djjb0ix2ve.png" alt="Choosing the installed Mono font" width="523" height="601"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>wsl2</category>
      <category>bash</category>
      <category>beautify</category>
    </item>
    <item>
      <title>Working with Node.js Entities and Mongoose Models - III</title>
      <dc:creator>Chiranjib</dc:creator>
      <pubDate>Mon, 20 Feb 2023 07:32:14 +0000</pubDate>
      <link>https://dev.to/chiranjib_b/working-with-nodejs-entities-and-mongoose-models-iii-1ge1</link>
      <guid>https://dev.to/chiranjib_b/working-with-nodejs-entities-and-mongoose-models-iii-1ge1</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;em&gt;Previous:&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt; &lt;a href="https://dev.to/chiranjib_b/working-with-nodejs-entities-and-mongoose-models-ii-4145"&gt;Working with Node.js Entities and Mongoose Models - II&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have established the entities, controllers, models and data-access for elementary CRUD operations, let's go ahead and add a few interactions. We have movies, we have users, now we need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;enable our users to rate movies&lt;/li&gt;
&lt;li&gt;fetch ratings for a movie&lt;/li&gt;
&lt;li&gt;fetch all ratings by a user&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 1 - edit our controller for picking up extensions as:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
    entityObject.getExtensions().forEach(function (extension) {
        router.use('/', extension);
    });

    return [`/${entityObject.name}`, router];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2 - create router extensions for entities
&lt;/h4&gt;

&lt;h6&gt;
  
  
  extension for rating movie
&lt;/h6&gt;

&lt;p&gt;Let's create a file &lt;code&gt;./entities/movie/extendedRouters/postRateMovie.js&lt;/code&gt; as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const router = require('express').Router({ mergeParams: true });
const MovieRatingModel = require('_data-access/models/MovieRating');

router.post('/rate', async function (req, res, next) {
    try {
        const { movie, user, rating } = req.body;
        const movieRating = await MovieRatingModel
            .findOneAndUpdate({
                movie, user
            }, {
                $set: {
                    rating
                }
            }, {
                upsert: true,
                new: true
            });
        res.json(movieRating);
    } catch (error) {
        next(error);
    }
});

module.exports = router;

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

&lt;/div&gt;



&lt;p&gt;The code above simply takes in the request body and persists it to the required collection. You may notice how it uses &lt;code&gt;findOneAndUpdate&lt;/code&gt;, &lt;code&gt;upsert: true&lt;/code&gt; and &lt;code&gt;new: true&lt;/code&gt;. This ensures that mongoose creates the document for us upon first access and helps ensure that there's only ever one combination of a movie and a user (enabling a user to modify their rating if they fancy).&lt;/p&gt;

&lt;h6&gt;
  
  
  extension for fetching movie ratings
&lt;/h6&gt;

&lt;p&gt;Let's create a file &lt;code&gt;./entities/movie/extendedRouters/getRatingsByMovieId.js&lt;/code&gt; as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const router = require('express').Router({ mergeParams: true });
const MovieRatingModel = require('_data-access/models/MovieRating');
const { Types: { ObjectId } } = require('mongoose');

router.get('/:movieId/ratings', async function (req, res, next) {
    try {
        const movieRatings = await MovieRatingModel.aggregate([
            {
                $match: { movie: new ObjectId(req.params.movieId) },
            },
            {
                $group: {
                    _id: '$movie',
                    ratings: { $push: '$rating' },
                    averageRating: { $avg: '$rating' },
                },
            },
        ]);
        res.json(movieRatings);
    } catch (error) {
        next(error);
    }
});

module.exports = router;

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

&lt;/div&gt;



&lt;p&gt;Now, we're getting a little fancy with our query. Notice now we have used &lt;code&gt;aggregate&lt;/code&gt; pipelines. There are multiple aggregation stages in Mongo and it takes some getting used to if you are transitioning from being a relational database user. Let us spend a moment on the pipelines here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;$match&lt;/code&gt; stage of the pipeline simply matches movie id of documents.&lt;/li&gt;
&lt;li&gt;the '$group' pipeline collects all the documents that pass the &lt;code&gt;$match&lt;/code&gt; stage, and &lt;code&gt;$push&lt;/code&gt; them into an Array &lt;code&gt;ratings&lt;/code&gt;, and also calculate the &lt;code&gt;$avg&lt;/code&gt; of those ratings as the field &lt;code&gt;averageRating&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h6&gt;
  
  
  extension for fetching all ratings by a user
&lt;/h6&gt;

&lt;p&gt;Let's create a file &lt;code&gt;./entities/user/extendedRouters/getRatingsByUserId.js&lt;/code&gt; as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const router = require('express').Router({ mergeParams: true });
const MovieRatingModel = require('_data-access/models/MovieRating');
const MovieModel = require('_data-access/models/Movie');
const {
    Types: { ObjectId },
} = require('mongoose');

router.get('/:userId/ratings', async function (req, res, next) {
    try {
        const movieRatingsByUser = await MovieRatingModel.aggregate([
            { $match: { user: new ObjectId(req.params.userId) } },
            {
                $group: {
                    _id: '$user',
                    records: {
                        $push: {
                            movie: '$movie',
                            rating: '$rating',
                        },
                    },
                },
            },
        ]);
        await MovieModel.populate(movieRatingsByUser, { path: 'records.movie', select: 'name' });
        res.json(movieRatingsByUser);
    } catch (error) {
        next(error);
    }
});

module.exports = router;

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

&lt;/div&gt;



&lt;p&gt;We have used the aggregate pipeline once again, let's understand what's happening once more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;$match&lt;/code&gt; stage matches the user id in question with the available documents&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;$group&lt;/code&gt; stage again collects all documents that pass the &lt;code&gt;$match&lt;/code&gt; stage, and &lt;code&gt;$push&lt;/code&gt; them into an array &lt;code&gt;records&lt;/code&gt; as an object having attributes &lt;code&gt;movie&lt;/code&gt; and &lt;code&gt;rating&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We decide to add a little more spice into our response, and decide that we will populate the Movie name in the response as well, because the person who processes the response would be able to make better sense of it. The line &lt;code&gt;await MovieModel.populate(movieRatingsByUser, { path: 'records.movie', select: 'name' });&lt;/code&gt; iterates all the documents that were received after the aggregate pipeline, and starts populating the &lt;code&gt;records.movie&lt;/code&gt; attribute for all of them with the 'Movie name' for relevance.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3 - make the entities return the router extensions
&lt;/h4&gt;

&lt;p&gt;Define the function &lt;code&gt;getExtentions&lt;/code&gt; in file &lt;code&gt;./entities/movie/index.js&lt;/code&gt; as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;getExtensions() {
        return [require('./extendedRouters/getRatingsByMovieId'), require('./extendedRouters/postRateMovie')];
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Define the function &lt;code&gt;getExtentions&lt;/code&gt; in file &lt;code&gt;./entities/user/index.js&lt;/code&gt; as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;getExtensions() {
        return [require('./extendedRouters/getRatingsByUserId')];
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, that's that. We have the entity interactions defined and fully functional.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;em&gt;Next:&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt; Typing...&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Working with Node.js Entities and Mongoose Models - II</title>
      <dc:creator>Chiranjib</dc:creator>
      <pubDate>Sun, 19 Feb 2023 14:14:52 +0000</pubDate>
      <link>https://dev.to/chiranjib_b/working-with-nodejs-entities-and-mongoose-models-ii-4145</link>
      <guid>https://dev.to/chiranjib_b/working-with-nodejs-entities-and-mongoose-models-ii-4145</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;em&gt;Previous:&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt; &lt;a href="https://dev.to/chiranjib_b/working-with-nodejs-entities-and-mongoose-models-i-1p05"&gt;Working with Node.js Entities and Mongoose Models - I&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The finish line is very close now, let's do it!&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1 - understand that the magic happens '&lt;em&gt;async&lt;/em&gt;'
&lt;/h4&gt;

&lt;p&gt;Node.js is single-threaded and JavaScript is asynchronous by design. If you don't know or understand how it works, then I'd strongly advise that you should familiarize with the concepts of asynchronous processing first. &lt;a href="https://dev.to/codeofrelevancy/all-about-promises-in-javascript-39lj"&gt;Here's a good explanation of the concepts.&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2 - modify our controller to support asynchronous processing
&lt;/h4&gt;

&lt;p&gt;In the file &lt;code&gt;./controllers/index.js&lt;/code&gt;, we need to make the router functions &lt;strong&gt;async&lt;/strong&gt;, and remember to &lt;strong&gt;await&lt;/strong&gt; before returning the response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const BaseEntity = require('_entities').getBaseEntity();
const logger = require('_utils/logger');

/**
 * 
 * @param {BaseEntity} entityObject 
 * @returns {[string, Router]}
 */
function getController(entityObject) {
    const router = require('express').Router({ mergeParams: true });
    router.post('/', async (req, res, next) =&amp;gt; {
        try {
            const response = await entityObject.create(req.body);
            res.json(response);
        } catch(e) {
            logger.error(e);
            res.status(500).send('Oops! Something went wrong!');
        }
    });

    router.get('/', async (req, res, next) =&amp;gt; {
        try {
            const response = await entityObject.read();
            res.json(response);
        } catch(e) {
            logger.error(e);
            res.status(500).send('Oops! Something went wrong!');
        }
    });

    router.get('/:entityObjectId', async (req, res, next) =&amp;gt; {
        try {
            const response = await entityObject.read(req.params.entityObjectId);
            res.json(response);
        } catch(e) {
            logger.error(e);
            res.status(500).send('Oops! Something went wrong!');
        }
    });

    router.put('/:entityObjectId', async (req, res, next) =&amp;gt; {
        try {
            const response = await entityObject.update(req.params.entityObjectId, req.body);
            res.json(response);
        } catch(e) {
            logger.error(e);
            res.status(500).send('Oops! Something went wrong!');
        }
    });

    router.delete('/:entityObjectId', async (req, res, next) =&amp;gt; {
        try {
            const response = await entityObject.delete(req.params.entityObjectId);
            res.json(response);
        } catch(e) {
            logger.error(e);
            res.status(500).send('Oops! Something went wrong!');
        }
    });

    return [`/${entityObject.name}`, router];
}

module.exports = {
    getController
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3 - Create entities for Movie and User
&lt;/h3&gt;

&lt;h6&gt;
  
  
  ./entities/movie/index.js
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const BaseEntity = require('_entities/BaseEntity');

module.exports = class MovieEntity extends BaseEntity {

    constructor() {
        super();
        this.name = 'Movie';
        this.model = require('_data-access/models/Movie');
    }

    async create(payload) {
        return await this.model.create(payload);
    }

    async read(id) {
        if (id) {
            return await this.model.findById(id).lean();
        } else {
            return await this.model.find().lean();
        }
    }

    async update(id, payload) {
        return await this.model.findByIdAndUpdate(id, payload, { new: true });
    }
};

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

&lt;/div&gt;



&lt;h6&gt;
  
  
  ./entities/user/index.js
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const BaseEntity = require('_entities/BaseEntity');

module.exports = class UserEntity extends BaseEntity {
    constructor() {
        super();
        this.name = 'User';
        this.model = require('_data-access/models/User');
    }

    async create(payload) {
        return await this.model.create(payload);
    }

    async read(id) {
        if (id) {
            return await this.model.findById(id).lean();
        } else {
            return await this.model.find().lean();
        }
    }

    async update(id, payload) {
        return await this.model.findByIdAndUpdate(id, payload, { new: true });
    }
};

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

&lt;/div&gt;



&lt;p&gt;Take note, both the entities are not supporting the &lt;code&gt;delete&lt;/code&gt; method, so the expectation is that if someone (could be a hacker) hits the DELETE endpoint, they would see that it is not supported.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 4 - generate controllers and expose them for the new entities
&lt;/h4&gt;

&lt;p&gt;In our &lt;code&gt;./index.js&lt;/code&gt; file, we have to make modifications to the &lt;code&gt;setupApp&lt;/code&gt; function as follows:&lt;br&gt;
&lt;/p&gt;

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

    app.use(...getController(entities.getEntityOne()));
    app.use(...getController(entities.getMovieEntity()));
    app.use(...getController(entities.getUserEntity()));

    app.use('/', (req, res) =&amp;gt; {
        res.send(`${req.originalUrl} can not be served`);
    });
....
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it! We have a fully functional persistent Node.js backend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;em&gt;Next:&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt; &lt;a href="https://dev.to/chiranjib_b/working-with-nodejs-entities-and-mongoose-models-iii-1ge1"&gt;Working with Node.js Entities and Mongoose Models - III&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Working with Node.js Entities and Mongoose Models - I</title>
      <dc:creator>Chiranjib</dc:creator>
      <pubDate>Sun, 19 Feb 2023 13:48:23 +0000</pubDate>
      <link>https://dev.to/chiranjib_b/working-with-nodejs-entities-and-mongoose-models-i-1p05</link>
      <guid>https://dev.to/chiranjib_b/working-with-nodejs-entities-and-mongoose-models-i-1p05</guid>
      <description>&lt;p&gt;Previous: &lt;a href="https://dev.to/chiranjib_b/integrate-nodejs-backend-with-mongodb-5834"&gt;Integrate Node.js Backend with MongoDB&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's reiterate the idea of our example application&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Our application maintains a database of movies, and their ratings by people. So, we are dealing with three entities: User (you or me), Movie (the things that require our time, money and attention) and Rating (link between User &amp;amp; Movie).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Step 1 - define Schemas and Models
&lt;/h4&gt;

&lt;p&gt;As can be deduced from above, let us create three (data-access) models:&lt;/p&gt;

&lt;h6&gt;
  
  
  ./data-access/models/User.js
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { Schema } = require('mongoose');
const { Types } = Schema;
const { getDBConnection } = require('_data-access/ConnectionFactory');

const UserSchema = new Schema(
    {
        email: { type: Types.String, required: true, unique: true },
        firstName: { type: Types.String },
        lastName: { type: Types.String },
    },
    {
        timestamps: true,
    }
);

module.exports = getDBConnection().model('user', UserSchema, null, {});

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

&lt;/div&gt;



&lt;h6&gt;
  
  
  ./data-access/models/Movie.js
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { Schema } = require('mongoose');
const { Types } = Schema;
const { getDBConnection } = require('_data-access/ConnectionFactory');

const Movie = new Schema(
    {
        name: { type: Types.String, required: true, unique: true },
        imdbLink: { type: Types.String, required: true, unique: true },
        rottenTomatoesLink: { type: Types.String, required: true, unique: true },
    },
    {
        timestamps: true,
    }
);

module.exports = getDBConnection().model('movie', Movie, null, {});

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

&lt;/div&gt;



&lt;h6&gt;
  
  
  ./data-access/models/MovieRating.js
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { Schema } = require('mongoose');
const { Types } = Schema;
const { getDBConnection } = require('_data-access/ConnectionFactory');

const MovieRating = new Schema(
    {
        movie: { type: Types.ObjectId, ref: require('./Movie'), required: true },
        user: { type: Types.ObjectId, ref: require('./User'), required: true },
        rating: { type: Types.Number, enum: [1, 2, 3, 4, 5] },
    },
    {
        timestamps: true,
    }
);

module.exports = getDBConnection().model('movierating', MovieRating, null, {});


module.exports = getDBConnection().model('movierating', MovieRating, null, {});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2 - define indices for faster data access
&lt;/h4&gt;

&lt;p&gt;This step is easy to miss, and it seems unnecessary, but it is something essential that can come back to bite people in the middle of the night when a customer data can't be loaded or the database starts sending high severity alerts because it is experiencing high I/O or is running out of memory.&lt;/p&gt;

&lt;p&gt;Now we're walking a slippery slope. Database indices are a two-edged sword. As the name suggests, think of indices as an index to a book. So, if there are edits to any page of a book or a new page gets added to the book, the index would have to be revised and recreated. That's why, while they enable faster data access, one too many indices will have I/O or memory implications of their own. Potentially, every document write will trigger refresh of the indices.&lt;/p&gt;

&lt;p&gt;That's why, it is important to imagine and define the data-access patterns in the application. With our example, here are the potential data queries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;find user by email&lt;/li&gt;
&lt;li&gt;find movie by name&lt;/li&gt;
&lt;li&gt;find how many users have rated a movie&lt;/li&gt;
&lt;li&gt;find how many movies a user has rated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Revisiting the Models and Schemas we have defined, let us define indices:&lt;/p&gt;

&lt;h6&gt;
  
  
  data-access/models/User.js
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UserSchema.index({ firstName: 1 }); // enable searching user by first name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;
  
  
  data-access/models/Movie.js
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Movie.index({ name: 1 }); // enable searching a movie by name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;
  
  
  data-access/models/MovieRating.js
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MovieRating.index({ movie: 1, user: 1 }); // enable searching movie-ratings by movie first, and then by specific user if required
MovieRating.index({ user: 1, movie: 1 }); // enable searching movie-ratings by users first, and then by specific movie if required
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, we are well-equipped to take the next step and achieve full sufficiency in our backend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;em&gt;Next:&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt; &lt;a href="https://dev.to/chiranjib_b/working-with-nodejs-entities-and-mongoose-models-ii-4145"&gt;Working with Node.js Entities and Mongoose Models - II&lt;/a&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>Integrate Node.js backend with MongoDB</title>
      <dc:creator>Chiranjib</dc:creator>
      <pubDate>Sun, 19 Feb 2023 13:09:43 +0000</pubDate>
      <link>https://dev.to/chiranjib_b/integrate-nodejs-backend-with-mongodb-5834</link>
      <guid>https://dev.to/chiranjib_b/integrate-nodejs-backend-with-mongodb-5834</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;em&gt;Previous:&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt; &lt;a href="https://dev.to/chiranjib_b/create-modular-routes-with-express-5cp9"&gt;Create modular routes with express&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have set up a Node.js backend with express.js and understand how we want to define our controllers and entities, it's time to make our setup more realistic. Our backend right now is missing a very crucial aspect - persistence (or in simple words, it needs a database).&lt;/p&gt;

&lt;p&gt;Staying true to our stack, let's integrate MongoDB. At this point, we should download and install MongoDB server. You may use this link: &lt;a href="https://www.mongodb.com/try/download/community" rel="noopener noreferrer"&gt;MongoDB Community Server&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To understand things fully, we have to come up with an example. Here's what we are going with:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Our application maintains a database of movies, and their ratings by people. So, we are dealing with three entities: User (you or me), Movie (the things that require our time, money and attention) and Rating (link between User &amp;amp; Movie).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Step 1 - get mongoose
&lt;/h4&gt;

&lt;p&gt;MongoDB is a schemaless database, which means you may store any JSON in any collection and a new onlooker can potentially be left absolutely mesmerized.&lt;br&gt;
Enter &lt;a href="https://www.npmjs.com/package/mongoose" rel="noopener noreferrer"&gt;mongoose&lt;/a&gt; - a library that provides Schemas and Models to make dealing with data on MongoDB a little more predictable.&lt;/p&gt;

&lt;p&gt;Let's navigate to our Node.js project root, and execute this&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm i --save mongoose&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Our package.json should have this new entry now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    "dependencies": {
        "express": "4.18.2",
        "helmet": "6.0.1",
        "link-module-alias": "1.2.0",
        "mongoose": "6.9.2",
        "winston": "3.8.2"
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2 - setting up for data-access
&lt;/h4&gt;

&lt;p&gt;Going back to the drawing board a little bit, let us establish a data-access module (folder) within our project.&lt;/p&gt;

&lt;p&gt;Create a data-access folder&lt;br&gt;
&lt;code&gt;mkdir ./data-access&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Data-access is again something that you are probably going to need throughout your application code, even in nested places. Let's set it up for access with absolute path. Add an entry in the &lt;code&gt;_moduleAliases&lt;/code&gt; section of &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    "_moduleAliases": {
        "_controllers": "./controllers",
        "_entities": "./entities",
        "_utils": "./utils",
        "_config": "./config",
        "_data-access": "./data-access"
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once done, we have to create the linkage of the new directory by executing&lt;br&gt;
&lt;code&gt;npm i&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Notice in the console output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; link-module-alias

link-module-alias: _controllers -&amp;gt; ./controllers, _entities -&amp;gt; ./entities, _utils -&amp;gt; ./utils, _config -&amp;gt; ./config, _data-access -&amp;gt; ./data-access
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3 - time to light it up
&lt;/h4&gt;

&lt;p&gt;Let's understand something trivial - the application will be in an impaired state if the database connection doesn't work. So, before anything else, our Node.js process should connect to the database and then start the app.&lt;/p&gt;

&lt;p&gt;Assuming that we are working with a local copy of MongoDB, let's modify the &lt;code&gt;./config/index.js&lt;/code&gt; file to include database details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
    DATABASE: {
        URL: 'mongodb://127.0.0.1',
        DB_NAME: 'moviemania'
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our sample application is very simplistic, but real world applications may work with multiple databases and multiple models. With that in consideration, it is a good practice to set up a data connection factory. Our implementation makes use of the &lt;em&gt;Factory Design Pattern&lt;/em&gt; and the &lt;em&gt;Singleton Design Pattern&lt;/em&gt;. Create a file &lt;code&gt;./data-access/ConnectionFactory.js&lt;/code&gt; as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { DATABASE: { URL, DB_NAME } } = require('_config');
const mongoose = require('mongoose');
/**
 * @type {mongoose.Connection}
 */
let dbConnection;

module.exports = {
    getDBConnection: function () {
        if (!dbConnection) {
            dbConnection = mongoose.connect(URL, { dbName: DB_NAME, maxPoolSize: 10 });
        }
        return dbConnection;
    },
    closeConnection: function () {
        if (dbConnection &amp;amp;&amp;amp; dbConnection.readyState === 1) {
            dbConnection.close();
        }
    }
};

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

&lt;/div&gt;



&lt;p&gt;We will have to refactor our &lt;code&gt;index.js&lt;/code&gt; as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one function to connect to the database&lt;/li&gt;
&lt;li&gt;another subsequent function that starts the app
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const logger = require('_utils/logger');

function connectToDB() {
    const { getDBConnection } = require('_data-access/ConnectionFactory');
    return new Promise((resolve, reject) =&amp;gt; {
        getDBConnection()
        .then(connection =&amp;gt; {
            let counter = 1;
            const timer = setInterval(function () {
                logger.info(`[${counter}] Checking connection..`);
                if (connection.readyState === 1) {
                    clearInterval(timer);
                    resolve();
                } else if (counter === 5) {
                    clearInterval(timer);
                    reject('Could not connect to database after 5 retries');
                }
                counter++;
            }, 1000);
        })
        .catch(e =&amp;gt; {
            logger.error(e)
            reject('Could not connect to database')
        });
    });
}

function setupApp() {
    const {
        SERVER: { PORT, REQUEST_BODY_SIZE_LIMIT },
    } = require('_config');
    const { getController } = require('_controllers');
    const helmet = require('helmet');
    const express = require('express');
    const entities = require('_entities');
    const app = express();

    app.use((req, res, next) =&amp;gt; {
        logger.log('info', `Received request [${req.method}] ${req.originalUrl}`);
        next();
    });

    app.use(helmet());
    app.use(express.json({ limit: REQUEST_BODY_SIZE_LIMIT }));
    app.use(express.urlencoded({ extended: true, limit: REQUEST_BODY_SIZE_LIMIT }));

    app.get('/healthcheck', (req, res) =&amp;gt; {
        res.send('OK');
    });

    app.use(...getController(entities.getEntityOne()));
    app.use(...getController(entities.getMovieEntity()));
    app.use(...getController(entities.getUserEntity()));

    app.use('/', (req, res) =&amp;gt; {
        res.send(`${req.originalUrl} can not be served`);
    });

    app.listen(PORT, () =&amp;gt; {
        logger.log('info', `Listening on port ${PORT}`);
    });
}

connectToDB()
    .then(function () {
        logger.info('Connected to database, starting app now...');
        setupApp();
    })
    .catch(function (e) {
        logger.error('Failed to connect to database.', e);
    });


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

&lt;/div&gt;



&lt;p&gt;If you notice carefully, our &lt;code&gt;connectToDB&lt;/code&gt; function returns a Promise. Only when the Promise is fulfilled would the next function &lt;code&gt;setupApp&lt;/code&gt; be invoked.&lt;/p&gt;

&lt;p&gt;So, we have set up a Node.js backend and connected to MongoDB. Next up, we will connect the dots between Controllers, Entities and Models.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;em&gt;Next:&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt; &lt;a href="https://dev.to/chiranjib_b/working-with-nodejs-entities-and-mongoose-models-i-1p05"&gt;Working with Node.js Entities and Mongoose Models - I&lt;/a&gt;&lt;/p&gt;

</description>
      <category>express</category>
      <category>node</category>
      <category>mongodb</category>
      <category>mongoose</category>
    </item>
    <item>
      <title>Setting up a Node.js backend</title>
      <dc:creator>Chiranjib</dc:creator>
      <pubDate>Tue, 14 Feb 2023 14:46:48 +0000</pubDate>
      <link>https://dev.to/chiranjib_b/setting-up-a-nodejs-backend-3o0a</link>
      <guid>https://dev.to/chiranjib_b/setting-up-a-nodejs-backend-3o0a</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;em&gt;Previous:&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt; &lt;a href="https://dev.to/chiranjib_b/learn-to-build-with-mern-stack-15a9"&gt;Learn to build with MERN stack&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;DISCLAIMER: This guide by no means aspires to be the holy grail. At the time of writing this I've been developing software for more than a decade and let's say I know of a few things that would make coding easy when it comes to basic principles like Readability, Maintainability, etc.&lt;br&gt;
P.S. If you don't like my suggestions, please don't hurl abuses at me, I have my friends for doing that. If you have some constructive feedback, please do share!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Step 1 - start the project and install a package
&lt;/h4&gt;

&lt;p&gt;Pick a folder on your device where you'd like to keep your code. It can be surprisingly easy to start a Node.js project. Open command terminal and navigate to the directory of your choice. Once there, execute this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;gt; npm init&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once you fill out the questionnaire, you should notice a &lt;em&gt;package.json&lt;/em&gt; file in your directory. You may want to read more about &lt;em&gt;npm&lt;/em&gt;, &lt;em&gt;npmrc&lt;/em&gt;, &lt;em&gt;package.json&lt;/em&gt; and &lt;em&gt;package-lock.json&lt;/em&gt; here: &lt;a href="https://docs.npmjs.com/about-npm" rel="noopener noreferrer"&gt;About npm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To get our feet wet, let's install a package - &lt;a href="https://www.npmjs.com/package/winston" rel="noopener noreferrer"&gt;winston&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;gt; npm install --save winston&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let's check our package.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;....
"dependencies": {
    "winston": "^3.8.2"
}
....
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the Caret (^) next to the version. This indicates winston should have any package compatible with &lt;code&gt;3.8.2&lt;/code&gt;. In some cases, this may present an unwanted problem. If we run &lt;code&gt;npm update&lt;/code&gt;, it can potentially upgrade the package to the next compatible version. I like to exercise a bit more control on the package and the versions I have. There are many ways to do this, I prefer using &lt;em&gt;npmrc&lt;/em&gt; for this.&lt;/p&gt;

&lt;p&gt;Let's create a file named &lt;code&gt;.npmrc&lt;/code&gt; as a sibling of &lt;code&gt;package.json&lt;/code&gt; and put this line in it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;save-exact=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to check all the options available for this file, check out &lt;a href="https://docs.npmjs.com/cli/v9/using-npm/config" rel="noopener noreferrer"&gt;npmrc config options&lt;/a&gt;&lt;br&gt;
Now, let's uninstall the package and install again&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; npm uninstall --save winston
&amp;gt; npm install --save winston
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the package.json has this now&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;....
"dependencies": {
    "winston": "3.8.2"
}
....
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sweet! We have a solid grip on all the package versions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2 - installing a few essentials
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; npm install --save express
&amp;gt; npm install --save-dev nodemon
&amp;gt; npm install --save-dev eslint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you notice, we've installed express with &lt;code&gt;--save&lt;/code&gt; and the other two with &lt;code&gt;--save-dev&lt;/code&gt;.&lt;br&gt;
The idea is to have some packages that are only required in our local setup while writing code. When it's time to release to production, the final version can be leaner to minimize the size of the shipment (more on that later). &lt;/p&gt;

&lt;p&gt;About the packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;express : popular library to define endpoints&lt;/li&gt;
&lt;li&gt;nodemon : popular for development as it watches files for changes and restarts the node process&lt;/li&gt;
&lt;li&gt;eslint : library required for enforcing code style guidelines&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Step 3 - set up linting
&lt;/h4&gt;

&lt;p&gt;It's essential to have a few rules to keep the code style consistent, eslint helps us do that. Let's set it up, run this command&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx eslint --init&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Answer the questions, specify your style of coding, and we're good to go. You may observe, a &lt;code&gt;.eslintrc.js&lt;/code&gt; file would have gotten created (provided you picked JavaScript as your option instead of JSON or YAML)&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 4 - create a few folders
&lt;/h4&gt;

&lt;p&gt;For the sake of sanity and keeping things modular, let's create the following directory structure to begin with. Don't worry about the content yet, we will focus on this as we move along.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/
  - config
  - controllers
  - entities
  - utils
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 5 - preparing for env variables
&lt;/h4&gt;

&lt;p&gt;It's a good practice to put all the variables in a single location, so that it's easier to refactor in the future. This may seem an overkill when we are just starting out, but as the application code grows and complexity increases, environment variables get messy and making changes can get tricky.&lt;br&gt;
Let's create a file &lt;code&gt;config/index.js&lt;/code&gt; and put the following content in it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
    SERVER: {
        PORT: 3000,
        REQUEST_BODY_SIZE_LIMIT: '10mb'
    },
    LOGGING: {
        LEVEL: 'warn'
    }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 6 - setting up project for absolute path
&lt;/h4&gt;

&lt;p&gt;One thing that quickly gets ugly, are relative file paths (require &lt;code&gt;../../../folder1/folder2/file1.js&lt;/code&gt;). Nowadays, there are many ways to get rid of it, here we'll explore one option.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm i --save link-module-alias&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Edit the package.json to add a &lt;code&gt;postinstall&lt;/code&gt; script and the &lt;code&gt;_moduleAliases&lt;/code&gt; section as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
    "scripts": {
        "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1",
        "postinstall": "link-module-alias"
    },
    "_moduleAliases": {
        "_controllers": "./controllers",
        "_entities": "./entities",
        "_utils": "./utils",
        "_config": "./config"
    }
....
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may run &lt;code&gt;npm i&lt;/code&gt; after this, and notice this in the console output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;....
&amp;gt; link-module-alias

link-module-alias: _controllers -&amp;gt; ./controllers, _entities -&amp;gt; ./entities, _utils -&amp;gt; ./utils, _config -&amp;gt; ./config
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we may use these as normal require statements like &lt;code&gt;require('_controllers')&lt;/code&gt; in any file within our project structure.&lt;/p&gt;

&lt;p&gt;In this post, I am only trying to highlight that you SHOULD enable something like this, by no means am I preaching that you use the same package.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 7 - specify start scripts
&lt;/h4&gt;

&lt;p&gt;We choose to run Node.js projects with npm commands instead of a simple command like &lt;code&gt;node index.js&lt;/code&gt; for the sake of consistency. Let's inject the following scripts in the &lt;code&gt;package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;....
"scripts": {
        "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1",
        "start": "node index.js",
        "dev": "nodemon index.js",
        "postinstall": "link-module-alias"
    }
....
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 8 - setting up the first endpoint
&lt;/h4&gt;

&lt;p&gt;Let's try to set up a healthcheck endpoint that simply responds with text "OK". First, let's enable us to use the logger library we integrated earlier. Create a file &lt;code&gt;utils/logger.js&lt;/code&gt; as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const winston = require('winston');
const { LOGGING: { LEVEL } } = require('_config');

const { combine, timestamp, prettyPrint, errors } = winston.format;

module.exports = winston.createLogger({
    format: combine(
        errors({ stack: true }),
        timestamp(),
        prettyPrint()
    ),
    level: LEVEL,
    transports: [
        new winston.transports.Console()
    ]
});

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

&lt;/div&gt;



&lt;p&gt;Now, we can focus on our route. Let's edit the index.js file as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { SERVER: { PORT } } = require('_config');
const logger = require('_utils/logger');

const express = require('express');

const app = express();

app.use((req, res, next) =&amp;gt; {
    logger.log('info', `Received request ${req.originalUrl}`);
    next();
});

app.get('/healthcheck', (req, res, next) =&amp;gt; {
    res.send('OK');
});

app.use('/', (req, res) =&amp;gt; {
    res.send(`${req.originalUrl} can not be served`);
});

app.listen(PORT, () =&amp;gt; {
    logger.log('info', `Listening on port ${PORT}`);
});

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

&lt;/div&gt;



&lt;p&gt;Few highlights of the simple snippet above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;all the statements defined for app, get executed in sequence&lt;/li&gt;
&lt;li&gt;we have defined a logger with winston that logs to the console for the sake of this example and restricted it to only &lt;code&gt;warn&lt;/code&gt; level using an environment variable. The line &lt;code&gt;logger.log('info'...&lt;/code&gt; won't print anything to the console until the level is set to &lt;code&gt;'info'&lt;/code&gt;. This comes in handy when in production we want to start printing more log statements to debug a problem. We can just change the environment variable on the fly.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app.use()&lt;/code&gt; statement in the beginning takes in a middleware that gets executed for any endpoint call that the app receives. This is useful for doing tasks like authentication, logging for audit, etc. The &lt;code&gt;next()&lt;/code&gt; call is crucial here to pass on the request chain to the next applicable middleware or endpoint definition as applicable&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app.get('/healthcheck')&lt;/code&gt; is the endpoint we intended to define, which simply responds with 'OK'&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app.use('/')&lt;/code&gt; is the fallback endpoint, that would catch all the requests that could not be served, and we can show graceful error messages if we desire&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To run the server, you need to execute either of the commands&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npm run start&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm run dev&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Voilà! We're all set! You may hit the endpoint we have just defined, and revel in the glory of your hard work.&lt;/p&gt;

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

&lt;p&gt;So, we have our boilerplate ready. Let's shape it up to be more robust and introduce modularity for more routes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;em&gt;Next:&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt; &lt;a href="https://dev.to/chiranjib_b/create-modular-routes-with-express-5cp9"&gt;Create modular routes with express&lt;/a&gt;&lt;/p&gt;

</description>
      <category>announcement</category>
      <category>devto</category>
      <category>web3</category>
      <category>crypto</category>
    </item>
    <item>
      <title>Create modular routes with express</title>
      <dc:creator>Chiranjib</dc:creator>
      <pubDate>Tue, 14 Feb 2023 14:46:12 +0000</pubDate>
      <link>https://dev.to/chiranjib_b/create-modular-routes-with-express-5cp9</link>
      <guid>https://dev.to/chiranjib_b/create-modular-routes-with-express-5cp9</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;em&gt;Previous:&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt; &lt;a href="https://dev.to/chiranjib_b/setting-up-a-nodejs-backend-3o0a"&gt;Setting up a Node.js backend&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;DISCLAIMER: This guide by no means aspires to be the holy grail. At the time of writing this I've been developing software for more than a decade and let's say I know of a few things that would make coding easy when it comes to basic principles like Readability, Maintainability, etc.&lt;br&gt;
P.S. If you don't like my suggestions, please don't hurl abuses at me, I have my friends for doing that. If you have some constructive feedback, please do share!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Assuming you have set up the Node.js backend boilerplate with express in accordance with the previous guide, let's go on and introduce some flavour.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1 - enable body-parser
&lt;/h4&gt;

&lt;p&gt;A crucial step before we dive into defining our routes, is to enable request body parsing in express. Mostly, the POST and PUT routes are expected to have a request body payload, and we need to be prepared to parse them.&lt;/p&gt;

&lt;p&gt;Express.js includes the body-parser package now, but we need to plug this in to the base express router. Stating the obvious, this statement needs to be plugged in before any of the routes start processing, with the assumption that all routes would require this functionality.&lt;br&gt;
One small detail to note here - we have introduced a new variable: &lt;code&gt;REQUEST_BODY_SIZE_LIMIT&lt;/code&gt;. This helps control the maximum allowed request body limit. As application grows complex, this helps put restraints in place according to available infrastructure resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
const { SERVER: { PORT, REQUEST_BODY_SIZE_LIMIT } } = require('_config');
...
app.use(express.json({ limit: REQUEST_BODY_SIZE_LIMIT }));
app.use(express.urlencoded({ extended: true, limit: REQUEST_BODY_SIZE_LIMIT }));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2 (optional) - implement some basic security measures
&lt;/h4&gt;

&lt;p&gt;Application security is non-negotiable. Thanks to the community, there's a package for this as well. The name is aptly selected - helmet. Put this on before you go for the ride 😉 😉&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm i --save helmet&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And we plug this in our code towards the beginning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
const helmet = require('helmet');
...
app.use(helmet());
app.use(bodyParser.json({ limit: REQUEST_BODY_SIZE_LIMIT }));
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3 - decide on the approach
&lt;/h4&gt;

&lt;p&gt;A very important but somewhat undervalued aspect of software development is to write code with a predefined structure. When the team size is small (&amp;lt;5), it seems manageable because communication is easier. But, as the team grows in size, people come in with different ideologies and beliefs. This has the potential of causing mayhem and a feeling like loss of identity.&lt;br&gt;
An instrument to facilitate the same is &lt;em&gt;Design Patterns&lt;/em&gt;. We will try to understand this step by step as we introduce our components.&lt;/p&gt;

&lt;p&gt;This is what we will follow for the purposes of this example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Entity: An object that supports CRUD operations&lt;/li&gt;
&lt;li&gt;Controller: The mechanism of exposing the CRUD operations of an entity via endpoints of the application&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Step 4 - define entities
&lt;/h4&gt;

&lt;p&gt;We will implement the &lt;em&gt;Decorator Design Pattern&lt;/em&gt; for our entities. The idea here is - our base entity will expose a few methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create()&lt;/li&gt;
&lt;li&gt;read()&lt;/li&gt;
&lt;li&gt;update()&lt;/li&gt;
&lt;li&gt;delete()&lt;/li&gt;
&lt;li&gt;getExtensions()&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each entity will have its name, which will be used to form the controller that exposes the routes associated with the entity. You may read debates on the internet about using classes versus functions in JavaScript, I would say use either that you like. We are defining entities with classes, just because I am comfortable this way.&lt;/p&gt;
&lt;h6&gt;
  
  
  Base Entity
&lt;/h6&gt;

&lt;p&gt;Create this file &lt;code&gt;entities/BaseEntity.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Router = require('express').Router;

/**
 * @class
 */
class BaseEntity {
    constructor() {
        this.name = 'BaseEntity';
        this.extensions = [];
    }

    /**
     * The child class is supposed to override this
     * @returns {Object}
     */
    create() {
        throw 'Not Supported';
    }

    /**
     * The child class is supposed to override this
     * @returns {Object | Array.&amp;lt;Object&amp;gt;}
     */
    read() {
        throw 'Not Supported';
    }

    /**
     * The child class is supposed to override this
     * @returns {Object}
     */
    update() {
        throw 'Not Supported';
    }

    /**
     * The child class is supposed to override this
     * @returns {Object}
     */
    delete() {
        throw 'Not Supported';
    }

    /**
     * The child class is supposed to override this
     * @returns {Array.&amp;lt;Router&amp;gt;}
     */
    getExtensions() {
        return this.extensions;
    }
}

module.exports = BaseEntity;

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

&lt;/div&gt;



&lt;h6&gt;
  
  
  Entity One
&lt;/h6&gt;

&lt;p&gt;We will set up our first Entity as a child of the BaseEntity. Create the file &lt;code&gt;entities\entity1\index.js&lt;/code&gt; as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const BaseEntity = require('_entities/BaseEntity');

module.exports = class EntityOne extends BaseEntity {
    constructor() {
        super();
        this.name = 'EntityOne';
        this.records = [
            { 'id': 1, 'key1': 'value1' },
            { 'id': 2, 'key2': 'value2' }
        ];
    }

    create(payload) {
        const lastObject = this.records[this.records.length - 1];
        this.records.push({ id: (lastObject?.id ?? 0) + 1, ...payload });
    }

    read(id) {
        if (id) {
            return this.records.find(record =&amp;gt; record.id === parseInt(id));
        } else {
            return this.records;
        }
    }

    update(id, payload) {
        const record = this.records.find(record =&amp;gt; record.id === parseInt(id));
        if (record) {
            const { _id, ...otherAttributes } = record;
            Object.assign(record, { ...otherAttributes, ...payload });
        }
    }

    delete(id) {
        const recordIndex = this.records.findIndex(record =&amp;gt; record.id === parseInt(id));
        if (recordIndex) {
            this.records.splice(recordIndex, 1);
        }
    }
};

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

&lt;/div&gt;



&lt;p&gt;Let's take a moment to see what we've done above. The BaseEntity defines CRUD methods with an error. The child entity creates overrides of the same methods, with the correct implementation. If the child does not create the implementation (intentionally or unintentionally), then the child would still respond with the implementation of the BaseEntity.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 5 - enable controller generation
&lt;/h4&gt;

&lt;p&gt;We will leverage the &lt;em&gt;Builder Design Pattern&lt;/em&gt; for enabling our controllers. Let's define a file &lt;code&gt;controllers\index.js&lt;/code&gt; as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const BaseEntity = require('_entities').getBaseEntity();
const logger = require('_utils/logger');

/**
 * 
 * @param {BaseEntity} entityObject 
 * @returns {[string, Router]}
 */
function getController(entityObject) {
    const router = require('express').Router({ mergeParams: true });
    router.post('/', async (req, res, next) =&amp;gt; {
        try {
            const response = await entityObject.create(req.body);
            res.json(response);
        } catch(e) {
            logger.error(e);
            res.status(500).send('Oops! Something went wrong!');
        }
    });

    router.get('/', async (req, res, next) =&amp;gt; {
        try {
            const response = await entityObject.read();
            res.json(response);
        } catch(e) {
            logger.error(e);
            res.status(500).send('Oops! Something went wrong!');
        }
    });

    router.get('/:entityObjectId', async (req, res, next) =&amp;gt; {
        try {
            const response = await entityObject.read(req.params.entityObjectId);
            res.json(response);
        } catch(e) {
            logger.error(e);
            res.status(500).send('Oops! Something went wrong!');
        }
    });

    router.put('/:entityObjectId', async (req, res, next) =&amp;gt; {
        try {
            const response = await entityObject.update(req.params.entityObjectId, req.body);
            res.json(response);
        } catch(e) {
            logger.error(e);
            res.status(500).send('Oops! Something went wrong!');
        }
    });

    router.delete('/:entityObjectId', async (req, res, next) =&amp;gt; {
        try {
            const response = await entityObject.delete(req.params.entityObjectId);
            res.json(response);
        } catch(e) {
            logger.error(e);
            res.status(500).send('Oops! Something went wrong!');
        }
    });

    return [`/${entityObject.name}`, router];
}

module.exports = {
    getController
};

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

&lt;/div&gt;



&lt;p&gt;This file defines a consistent way of generating endpoints. The idea is - to define controllers, we will be forced to think in terms of entities, which in turn facilitates greater control on CRUD operations.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 5 - generate controllers with entities
&lt;/h4&gt;

&lt;p&gt;We are good to have our first entity based controller. Let's modify the index.js as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
const { getController } = require('_controllers');
...
app.get('/healthcheck', (req, res, next) =&amp;gt; {
    res.send('OK');
});

app.use(...getController(new EntityOne()));

app.use('/', (req, res) =&amp;gt; {
    res.send(`${req.originalUrl} can not be served`);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we plug this in, EntityOne would expose four routes as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;POST /EntityOne&lt;/li&gt;
&lt;li&gt;GET /EntityOne&lt;/li&gt;
&lt;li&gt;PUT /EntityOne&lt;/li&gt;
&lt;li&gt;DELETE /EntityOne&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's all for this one. In the next one, we will add more flavours to our setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;em&gt;Next:&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt; &lt;a href="https://dev.to/chiranjib_b/integrate-nodejs-backend-with-mongodb-5834"&gt;Integrate Node.js backend with MongoDB&lt;/a&gt;&lt;/p&gt;

</description>
      <category>express</category>
      <category>node</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Learn to build with MERN stack</title>
      <dc:creator>Chiranjib</dc:creator>
      <pubDate>Mon, 16 Jan 2023 07:27:25 +0000</pubDate>
      <link>https://dev.to/chiranjib_b/learn-to-build-with-mern-stack-15a9</link>
      <guid>https://dev.to/chiranjib_b/learn-to-build-with-mern-stack-15a9</guid>
      <description>&lt;p&gt;Assumption: You already know a few things, viz:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basics of JavaScript, and that it has no connection to Java at all&lt;/li&gt;
&lt;li&gt;What servers are, and the language(s) they speak. For this one, you only need to know about HTTP&lt;/li&gt;
&lt;li&gt;Node.js exists, and that it uses JavaScript. Also, you should have installed it already. If not, here's the link that saves you a search: &lt;a href="https://nodejs.org/en/download/" rel="noopener noreferrer"&gt;Node.js download&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Facebook is not just good for mindless scrolling, it also gave us React.js&lt;/li&gt;
&lt;li&gt;MongoDB is a database that loves JSON and isn't serious about relationships&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide is a stepping stone for wannabe developers who have chosen to build with the MERN stack. I know that Typescript is a thing, but to keep things introductory I have gone with JavaScript. Maybe people will tell you that you are not cool enough if you don't use Typescript, but my response to such remarks usually is - &lt;em&gt;Users of a website don't care if you have used JavaScript or C; what matters to them is whether the button does what it should do when they click it&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Before beginning, I feel I should announce that the series of posts I am linking later, do not go into great detail of the concepts but do touch a lot of them. I have tried to mention the "why" in mostly, but even then if some part leaves you wondering about stuff in general, please do reach out and I'll try to answer your question.&lt;/p&gt;

&lt;p&gt;Alright, enough preaching! Crack your knuckles and let's get into it. We will begin by setting up a Node.js backend&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;&lt;em&gt;Next:&lt;/em&gt;&lt;/u&gt;&lt;/strong&gt; &lt;a href="https://dev.to/chiranjib_b/setting-up-a-nodejs-backend-3o0a"&gt;Setting Up a Node.js Backend&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>marketing</category>
      <category>softwaredevelopment</category>
    </item>
  </channel>
</rss>
