<?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: Josu Martinez</title>
    <description>The latest articles on DEV Community by Josu Martinez (@josuto).</description>
    <link>https://dev.to/josuto</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%2F984590%2F8329bb8f-430e-4e0a-8263-7078f42da1c8.jpeg</url>
      <title>DEV Community: Josu Martinez</title>
      <link>https://dev.to/josuto</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/josuto"/>
    <language>en</language>
    <item>
      <title>Lightweight Abstract Repository for NestJS</title>
      <dc:creator>Josu Martinez</dc:creator>
      <pubDate>Wed, 19 Jul 2023 16:00:00 +0000</pubDate>
      <link>https://dev.to/josuto/lightweight-generic-repository-for-nestjs-38fi</link>
      <guid>https://dev.to/josuto/lightweight-generic-repository-for-nestjs-38fi</guid>
      <description>&lt;p&gt;In this article, I will explain how to develop a sample application using NestJS and MongoDB, leveraging the functionalities provided by the &lt;a href="https://www.npmjs.com/package/monguito"&gt;&lt;code&gt;monguito&lt;/code&gt;&lt;/a&gt;, a lightweight and type-safe library to seamlessly create custom database repositories for Node.js applications.&lt;/p&gt;

&lt;p&gt;The sample application is a book manager that includes features such as creating, updating, deleting, and finding books. I will also provide step-by-step instructions for installing and running the application.&lt;/p&gt;

&lt;p&gt;For those eager to get to the code of the sample application, you can find it at &lt;a href="https://github.com/Josuto/monguito/tree/main/examples/nestjs-mongoose-book-manager"&gt;this Github repository&lt;/a&gt;. You may also find a further explanation on the &lt;code&gt;monguito&lt;/code&gt; library at &lt;a href="https://dev.to/josuto/node-abstract-repository-for-mongodb-50jn"&gt;this other article&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Domain Model
&lt;/h2&gt;

&lt;p&gt;The application domain model is pretty simple: &lt;code&gt;Book&lt;/code&gt; is a supertype that specifies two subclasses i.e., &lt;code&gt;PaperBook&lt;/code&gt; and &lt;code&gt;AudioBook&lt;/code&gt;. Here is its definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Book&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Entity&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;id&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;readonly&lt;/span&gt; &lt;span class="nx"&gt;title&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;readonly&lt;/span&gt; &lt;span class="nx"&gt;description&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;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;id&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;title&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;description&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="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;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&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;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&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="nx"&gt;PaperBook&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Book&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;edition&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="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paperBook&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;id&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;title&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;description&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;edition&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="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="nx"&gt;paperBook&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;edition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;paperBook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;edition&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="nx"&gt;AudioBook&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Book&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;hostingPlatforms&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;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;audioBook&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;id&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;title&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;description&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;hostingPlatforms&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="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="nx"&gt;audioBook&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;hostingPlatforms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;audioBook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hostingPlatforms&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://github.com/Josuto/monguito/blob/main/src/util/entity.ts"&gt;&lt;code&gt;Entity&lt;/code&gt;&lt;/a&gt; is an interface created to assist developers in the implementation of type-safe domain models. It specifies an &lt;code&gt;id&lt;/code&gt; field that all &lt;code&gt;Book&lt;/code&gt; or subclass instances must include. This is because &lt;code&gt;id&lt;/code&gt; is assumed to be the primary key of any stored book. However, you do not need to implement &lt;code&gt;Entity&lt;/code&gt; if you do not want to; simply make sure that your superclass includes an &lt;code&gt;id&lt;/code&gt; field in its definition.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Repository
&lt;/h2&gt;

&lt;p&gt;Here a simple definition of a custom repository for books:&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="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="nx"&gt;MongooseBookRepository&lt;/span&gt;
  &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;MongooseRepository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Book&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Repository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Book&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;constructor&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;InjectConnection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="na"&gt;connection&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="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="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="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="nx"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BookSchema&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;PaperBook&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PaperBook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PaperBookSchema&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;AudioBook&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AudioBook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AudioBookSchema&lt;/span&gt; &lt;span class="p"&gt;},&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="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://github.com/Josuto/monguito/blob/main/src/repository.ts"&gt;&lt;code&gt;Repository&lt;/code&gt;&lt;/a&gt; is a Typescript generic interface that specifies some common CRUD database operations that can be executed on any persistent domain object. &lt;a href="https://github.com/Josuto/monguito/blob/main/src/mongoose.repository.ts"&gt;&lt;code&gt;MongooseRepository&lt;/code&gt;&lt;/a&gt;, on another hand, is a Mongoose-based implementation of the interface that provides you with all the boilerplate code required to execute those operations. You can find further details on both &lt;code&gt;Repository&lt;/code&gt; and &lt;code&gt;MongooseRepository&lt;/code&gt; in this &lt;a href="https://dev.to/josuto/node-abstract-repository-for-mongodb-50jn"&gt;article&lt;/a&gt;. I would personally recommend you read the section &lt;em&gt;Some Important Implementation Details&lt;/em&gt; to gain some required knowledge on the logic expected for your custom repository constructor, specially if your domain model is &lt;em&gt;polymorphic&lt;/em&gt; i.e., if you want to store instances of a type and/or its subtypes in the same MongoDB collection.&lt;/p&gt;

&lt;p&gt;You may also have some further questions regarding the &lt;code&gt;Injectable&lt;/code&gt; and &lt;code&gt;InjectConnection&lt;/code&gt; decorators. Please be patient, I will address them soon enough in this article 😉.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Controller
&lt;/h2&gt;

&lt;p&gt;The controller is the entry point of external requests to the book manager application. Here is how it looks like:&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;type&lt;/span&gt; &lt;span class="nx"&gt;PartialBook&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Book&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;function&lt;/span&gt; &lt;span class="nx"&gt;deserialise&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="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Book&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;plainBook&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;book&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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;plainBook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;edition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;book&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;PaperBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plainBook&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plainBook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hostingPlatforms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;book&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;AudioBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plainBook&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;book&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;Book&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plainBook&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;book&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;Controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;books&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="nx"&gt;BookController&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="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BOOK_REPOSITORY&lt;/span&gt;&lt;span class="dl"&gt;'&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;bookRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Repository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Book&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;findAll&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Book&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bookRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findAll&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;Post&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Body&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="nx"&gt;plainBook&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;deserialise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plainBook&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Book&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;book&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;Patch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PartialBook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Book&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;book&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;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;deleteById&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;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;id&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bookRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deleteById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Book&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;PartialBook&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Book&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;try&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;await&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;bookRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BadRequestException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="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;You may argue several things here. For starters, you may think that an enterprise application should delegate business/domain logic to a layer of service objects as described in e.g., &lt;a href="https://enterprisecraftsmanship.com/posts/domain-vs-application-services/"&gt;Domain-Driven Design (tactical design)&lt;/a&gt;. I have decided not to do so for simplicity purposes; the book manager presented in this article is such an extremely simple CRUD application that introducing services would be over-engineering. I rather implement the minimum amount of code necessary for the sake of maximising the actual purpose of the article: illustrate how to integrate the &lt;a href="https://www.npmjs.com/package/monguito"&gt;&lt;code&gt;monguito&lt;/code&gt;&lt;/a&gt; library on a NodeJS-based enterprise application.&lt;/p&gt;

&lt;p&gt;Moreover, you would probably not write a &lt;code&gt;deserialise&lt;/code&gt; function to enable the transformation of JSON request bodies into domain objects when dealing with &lt;code&gt;POST&lt;/code&gt; requests. Instead, you would rather use a &lt;a href="https://docs.nestjs.com/pipes#pipes"&gt;NestJS pipe&lt;/a&gt; to do so, thus properly complying with the Single Responsibility principle. Once again, I wanted to share the simplest possible working example at the expense of not conveying to the recommended practices in NestJS application construction. That being said, I would highly recommend you to read &lt;a href="https://docs.nestjs.com/pipes#class-validator"&gt;this section&lt;/a&gt; on how to use &lt;code&gt;class-validator&lt;/code&gt; and &lt;code&gt;class-transformer&lt;/code&gt; for the validation and deserialisation of JSON request bodies in the development of complex enterprise applications.&lt;/p&gt;

&lt;p&gt;Okay! So all is missing now is how to tell the controller to use the custom book repository at runtime. This is where we are going next.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Application Module
&lt;/h2&gt;

&lt;p&gt;NestJS implements the Dependency Inversion principle; developers specify their component dependencies and NestJS uses its built-in dependency injector to inject those dependencies during component instantiation. &lt;/p&gt;

&lt;p&gt;So, how do we specify the dependencies of the components that compose the book manager sample application? There are two easy steps that we need to take: The first step consists of writing some decorators in the &lt;code&gt;MongooseBookRepository&lt;/code&gt; and &lt;code&gt;BookController&lt;/code&gt; classes, as I already did in the code definition for both. The former class specifies that its instances are &lt;code&gt;Injectable&lt;/code&gt; to other components. It also specifies that to instantiate a book repository, NestJS needs to inject a Mongoose connection. This is done with the &lt;code&gt;InjectConnection&lt;/code&gt; decorator related to the &lt;code&gt;connection&lt;/code&gt; constructor input parameter. &lt;/p&gt;

&lt;p&gt;On another hand, the definition of &lt;code&gt;BookController&lt;/code&gt; specifies that, during instantiation, the controller consumes an instance of a &lt;code&gt;Repository&amp;lt;Book&amp;gt;&lt;/code&gt; defined by the &lt;code&gt;BOOK_REPOSITORY&lt;/code&gt; custom token. &lt;/p&gt;

&lt;p&gt;The definition of the custom token is part of the second step: writing the last required class: &lt;code&gt;AppModule&lt;/code&gt;. The definition of this class is 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="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;MongooseModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongodb://localhost:27016/book-repository&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;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BOOK_REPOSITORY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;useClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MongooseBookRepository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;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;BookController&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="nx"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Module&lt;/code&gt; decorator of this class specifies the Mongoose connection required to instantiate &lt;code&gt;MongooseBookRepository&lt;/code&gt; at the &lt;code&gt;imports&lt;/code&gt; property. It also determines that any component that has a dependency with the &lt;code&gt;provider&lt;/code&gt; identified by the &lt;code&gt;BOOK_REPOSITORY&lt;/code&gt; custom token is to get an instance of &lt;code&gt;MongooseBookRepository&lt;/code&gt;. Finally, it determines that &lt;code&gt;BookController&lt;/code&gt; is the sole controller for the book manager application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the Application
&lt;/h2&gt;

&lt;p&gt;Once you have implemented the book manager in your own or cloned the &lt;code&gt;monguito&lt;/code&gt; &lt;a href="https://github.com/Josuto/monguito"&gt;GitHub project&lt;/a&gt;, and assuming that you have NestJS installed in your local machine, there are two further prerequisites to satisfy before you can run the application.&lt;/p&gt;

&lt;p&gt;You must install all the project dependencies specified at the &lt;code&gt;package.json&lt;/code&gt; file. To do so, simply execute the &lt;code&gt;yarn install&lt;/code&gt; command from the root folder of the project. If you have cloned the library project, that folder is &lt;code&gt;examples/nestjs-mongoose-book-manager&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The second prerequisite is installing Docker Desktop (in case you have not done it yet) and launching it in your local machine. I wrote a &lt;a href="https://github.com/Josuto/monguito/blob/main/examples/nestjs-mongoose-book-manager/docker-compose.yml"&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt; file&lt;/a&gt; to create a Docker container with an instance of the latest MongoDB version for your convenience, but you may create your own otherwise.&lt;/p&gt;

&lt;p&gt;Then, all you need to do is run &lt;code&gt;yarn start:dev&lt;/code&gt;. You will then be able to access all the endpoints specified at &lt;code&gt;BookController&lt;/code&gt; via e.g., the &lt;code&gt;curl&lt;/code&gt; command or Postman.&lt;/p&gt;

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

&lt;p&gt;After following the several steps required to build an easy web application that integrates &lt;a href="https://www.npmjs.com/package/monguito"&gt;&lt;code&gt;monguito&lt;/code&gt;&lt;/a&gt;, I hope that you are now able to leverage your knowledge and build your own. If you are willing to create a complex application, I also hope I has been able to provide you with a bit of guidance. Otherwise, please leave me a comment and I will get back to you ASAP 😊.&lt;/p&gt;

&lt;p&gt;Cover image by &lt;a href="https://unsplash.com/@michaelsum1228?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Michael Sum&lt;/a&gt; on &lt;a href="https://unsplash.com/images/animals/cat?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>mongodb</category>
      <category>nestjs</category>
    </item>
    <item>
      <title>MongoDB Abstract Repository for Node</title>
      <dc:creator>Josu Martinez</dc:creator>
      <pubDate>Sun, 04 Jun 2023 16:54:17 +0000</pubDate>
      <link>https://dev.to/josuto/node-abstract-repository-for-mongodb-50jn</link>
      <guid>https://dev.to/josuto/node-abstract-repository-for-mongodb-50jn</guid>
      <description>&lt;p&gt;&lt;a href="https://www.npmjs.com/package/monguito"&gt;&lt;code&gt;monguito&lt;/code&gt;&lt;/a&gt; is a lightweight and type-safe library to seamlessly create custom database repositories for Node.js applications. It provides developers with some built-in CRUD operations, enabling them to focus in adding their own operations, and ensures a clean separation between persistence and domain logic. Despite being database technology agnostic by nature, it currently includes an implementation for MongoDB.&lt;/p&gt;

&lt;h3&gt;
  
  
  Note
&lt;/h3&gt;

&lt;p&gt;This article introduces &lt;code&gt;monguito&lt;/code&gt;, but it does not include all of its details. You may find the full documentation and some usage examples at &lt;a href="https://github.com/Josuto/monguito"&gt;this GitHub repository&lt;/a&gt;, including an example of &lt;a href="https://github.com/Josuto/monguito/tree/main/examples/nestjs-mongoose-book-manager"&gt;how to use this library in a NestJS-based application&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Build Yet Another Repository Library
&lt;/h2&gt;

&lt;p&gt;Joining &lt;a href="https://www.climatepartner.com/"&gt;ClimatePartner&lt;/a&gt; made me switch my gears and start to develop JS/TS-based web applications. My very first assignment was connecting a small backend NestJS app with a MongoDB database. We had big plans for our app and we soon realised that the domain model owned by my team was going to grow in complexity, and quickly. Furthermore, we saw that this was also the reality in other teams that wanted to use the same kind of solution.&lt;/p&gt;

&lt;p&gt;All considered, we decided to incorporate a database access utility that implements the &lt;a href="https://www.martinfowler.com/eaaCatalog/repository.html"&gt;Repository pattern&lt;/a&gt; to cleanly decouple persistence from domain logic while keeping query logic duplication to the bare minimum. We also wanted it to be of &lt;em&gt;abstract&lt;/em&gt; nature so that we could reuse the database access logic that is common to all custom repositories (i.e., CRUD operations over any persistent domain object). Finally, we needed it to implement the  &lt;a href="https://www.mongodb.com/developer/products/mongodb/polymorphic-pattern/"&gt;Polymorphic pattern&lt;/a&gt; to support subtyping-based domain models.&lt;/p&gt;

&lt;p&gt;So we started researching the state-of-the-art and discovered several libraries that could fit our requirements. The best candidates we were able to find were &lt;a href="https://mongoosejs.com/"&gt;Mongoose&lt;/a&gt;, &lt;a href="https://typegoose.github.io/typegoose/"&gt;Typegoose&lt;/a&gt;, and &lt;a href="https://typeorm.io/"&gt;TypeORM&lt;/a&gt;. Mongoose is a well-known Node.js library for MongoDB that implements the &lt;a href="https://martinfowler.com/eaaCatalog/dataMapper.html"&gt;Data Mapper pattern&lt;/a&gt; and lets developers define schemas to constraint the data models associated with their domain objects. However, Mongoose works with concrete data models, which in a complex domain model scenario results in query logic duplication. Typegoose is a type-safe Mongoose wrapper that allows schema constraint declaration at domain object field level via JS decorators. Unfortunately, those very decorators leak persistence logic into the domain model. Besides, Typegoose also implements the Data Mapper pattern, thus sharing the same drawbacks of Mongoose. TypeORM, on another hand, implements the Repository pattern and provides some basic support for MongoDB. However, TypeORM &lt;a href="https://eliezer.medium.com/typeorm-mongodb-review-8855903228b1"&gt;presents several limitations compared to Mongoose&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Although none of the existing alternatives were exactly fitting our needs, we saw value on Mongoose's solid, well-documented, and complete set of features. On the top of that, we wanted the most lightweight solution possible. That's why we decided to create &lt;code&gt;monguito&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cut to the Chase
&lt;/h2&gt;

&lt;p&gt;Say we have a domain model that specifies &lt;code&gt;Book&lt;/code&gt; as the supertype domain object and &lt;code&gt;PaperBook&lt;/code&gt; and &lt;code&gt;AudioBook&lt;/code&gt; as subtypes. Here is one possible definition for that domain model:&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="nx"&gt;Book&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;Entity&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;id&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;readonly&lt;/span&gt; &lt;span class="nx"&gt;title&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;readonly&lt;/span&gt; &lt;span class="nx"&gt;description&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;readonly&lt;/span&gt; &lt;span class="nx"&gt;isbn&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;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;id&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;title&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;description&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;isbn&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="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;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&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;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&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;isbn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isbn&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;class&lt;/span&gt; &lt;span class="nx"&gt;PaperBook&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Book&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;edition&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="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paperBook&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;id&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;title&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;description&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;isbn&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;edition&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="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="nx"&gt;paperBook&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;edition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;paperBook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;edition&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;class&lt;/span&gt; &lt;span class="nx"&gt;AudioBook&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Book&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;hostingPlatforms&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;readonly&lt;/span&gt; &lt;span class="nx"&gt;format&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;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;audioBook&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;id&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;title&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;description&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;isbn&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;hostingPlatforms&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="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="nx"&gt;audioBook&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;hostingPlatforms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;audioBook&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hostingPlatforms&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, you want to be able to persist and retrieve instances of &lt;code&gt;Book&lt;/code&gt; and any of its subtypes from a MongoDB database. &lt;code&gt;MongooseBookRepository&lt;/code&gt; is a custom repository that specifies &lt;code&gt;Book&lt;/code&gt;-related database operations. Here is its definition:&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="nx"&gt;MongooseBookRepository&lt;/span&gt;
  &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;MongooseRepository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Book&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;BookRepository&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="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="na"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BookSchema&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;PaperBook&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PaperBook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PaperBookSchema&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;AudioBook&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AudioBook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AudioBookSchema&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="nx"&gt;findByIsbn&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="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Book&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;isbn&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Optional&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;&amp;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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isbn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The given ISBN must be valid&lt;/span&gt;&lt;span class="dl"&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;entityModel&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;isbn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isbn&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;book&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;Optional&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ofNullable&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;instantiateFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Voilà! &lt;code&gt;MongooseBookRepository&lt;/code&gt; inherits a series of CRUD database operations from &lt;code&gt;MongooseRepository&lt;/code&gt; and adds its own i.e., &lt;code&gt;findByIsbn&lt;/code&gt;. Now you can simply instantiate &lt;code&gt;MongooseBookRepository&lt;/code&gt; and execute any of the database operations 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;const&lt;/span&gt; &lt;span class="nx"&gt;bookRepository&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;MongooseBookRepository&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;books&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bookRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No more leaking of persistence logic into your domain/application logic!&lt;/p&gt;

&lt;h3&gt;
  
  
  Some Important Implementation Details
&lt;/h3&gt;

&lt;p&gt;You may be wondering about certain elements exposed in the previous example. Starting from the top part of the &lt;code&gt;MongooseBookRepository&lt;/code&gt; definition, the first of these is &lt;code&gt;MongooseRepository&amp;lt;Book&amp;gt;&lt;/code&gt;. This is one of the two main elements exposed at &lt;code&gt;monguito&lt;/code&gt;: a generic template that implements several common CRUD database operations. Furthermore, this class also handles the creation of a Mongoose data model capable of handling subtyping-based book data objects. All this complexity is hidden from you; all you need to know is that you have &lt;code&gt;entityModel&lt;/code&gt; at your disposal to implement your own database operations, as shown at &lt;code&gt;findByIsbn&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The only extra effort required is that you define a map that specifies the types that compose your domain model and their related Mongoose &lt;a href="https://mongoosejs.com/docs/guide.html"&gt;schemas&lt;/a&gt;, as specified at the constructor of &lt;code&gt;MongooseBookRepository&lt;/code&gt;. It is also important to note that the key of the entry that specifies your domain object supertype must be named &lt;code&gt;Default&lt;/code&gt;, and the key of each other entry must be named after the type name of the subtype domain object it refers to. This is a naming convention required by the inner implementation details of &lt;code&gt;MongooseRepository&lt;/code&gt;. If you do not have any domain object subtype in your domain model then simply instantiate a map with a unique entry that specifies a &lt;code&gt;Default&lt;/code&gt; key and the type-schema values of your domain object.&lt;/p&gt;

&lt;p&gt;Another element that may catch your eye is &lt;code&gt;BookRepository&lt;/code&gt;. This is an optional interface that extends &lt;code&gt;Repository&lt;/code&gt;, the second main element exposed at &lt;code&gt;monguito&lt;/code&gt;: a database technology agnostic generic interface that specifies all the supported CRUD database operations to be implemented by any repository. The following snippet shows this relation between these two interfaces:&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;interface&lt;/span&gt; &lt;span class="nx"&gt;BookRepository&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Repository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Book&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;findByIsbn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Book&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;isbn&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Optional&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;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Handling instances of interface types instead of classes is a good practice in object-oriented applications; &lt;a href="https://en.wikipedia.org/wiki/Dependency_inversion_principle"&gt;depending on abstractions instead of implementations&lt;/a&gt; makes your code scalable and better suited to change. Therefore, I would highly recommend that you define your own repository interfaces, or in the case you are only interested in exposing CRUD operations, instantiate your custom repositories as objects of type &lt;code&gt;Repository&amp;lt;T&amp;gt;&lt;/code&gt;, where &lt;code&gt;T&lt;/code&gt; is your domain object supertype.&lt;/p&gt;

&lt;p&gt;On another hand, &lt;code&gt;Book&lt;/code&gt; implements an interface called &lt;code&gt;Entity&lt;/code&gt;. This interface models any persistent domain object type. The interface defines an optional &lt;code&gt;id&lt;/code&gt; field. The optional nature of the field is due to the fact that its value is internally set by Mongoose. If you do not want your domain model to include this dependency, though, you can just ensure that your domain objects specify an &lt;code&gt;id?: string&lt;/code&gt; field. And there is nothing wrong doing that, as &lt;code&gt;id&lt;/code&gt; is the canonical primary key in MongoDB documents.&lt;/p&gt;

&lt;p&gt;Finally, many database operations return objects of type &lt;a href="https://www.npmjs.com/package/typescript-optional"&gt;&lt;code&gt;Optional&lt;/code&gt;&lt;/a&gt;. This type is inspired in the &lt;a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Optional.html"&gt;Java &lt;code&gt;Optional&lt;/code&gt; type&lt;/a&gt;. Its purpose is to model the concept of "no result". This type is an excellent alternative to returning &lt;code&gt;null&lt;/code&gt; objects or throwing an exception. The usage of &lt;code&gt;Optional&lt;/code&gt; is safer and clearer than having to specify &lt;code&gt;T | null&lt;/code&gt; as result type or &lt;a href="https://github.com/EnosMatika/effective-java-3e/blob/master/10_exceptions/item_69_use_exceptions_only_for_exceptional_conditions.md"&gt;having to handle an exception that does not represent an application exceptional condition&lt;/a&gt;. So yes, this the feature that makes &lt;code&gt;monguito&lt;/code&gt; a bit opinionated, but I believe that is worth it.&lt;/p&gt;

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

&lt;p&gt;The &lt;code&gt;monguito&lt;/code&gt; library provides the means to  create custom repositories for Node.js-based applications in a fast and easy manner. It is conceived to achieve effective decoupling between persistence and domain logic. Its current implementation is a Mongoose wrapper that includes all the boilerplate code required to perform common CRUD operations over polymorphic domain objects in MongoDB. Thus, developers can focus in writing domain-specific database operations at custom repositories.&lt;/p&gt;

&lt;p&gt;Moreover, the library has been designed to allow developers use many interesting Mongoose features (e.g., creation and validation of polymorphic models as well as hook implementations, just two mention two) without having to deal with most of Mongoose's inner complexity.&lt;/p&gt;

&lt;p&gt;Cover image by &lt;a href="https://unsplash.com/@alevisionco?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Alev Takil&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/d-1FY75fh_s?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>webdev</category>
      <category>mongodb</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Effective TDD</title>
      <dc:creator>Josu Martinez</dc:creator>
      <pubDate>Mon, 05 Dec 2022 12:43:51 +0000</pubDate>
      <link>https://dev.to/josuto/effective-tdd-3hii</link>
      <guid>https://dev.to/josuto/effective-tdd-3hii</guid>
      <description>&lt;p&gt;It has been six months since I started working at &lt;a href="https://www.climatepartner.com/"&gt;ClimatePartner&lt;/a&gt; building a new enterprise application. My new team follows some agile practices such as pair programming and Test-Driven Development (TDD), and I have the honest feeling that the sun is shining for us!&lt;/p&gt;

&lt;p&gt;Well, almost.&lt;/p&gt;

&lt;p&gt;There are some issues that I have been facing both now and in past industrial experiences on the topic of building solid enterprise applications that I would like to explain to you in this article.&lt;/p&gt;

&lt;p&gt;Furthermore, I will also propose a simple test-first-based methodology to build enterprise applications that enhance team communication and promote faster high-quality code deliveries.&lt;/p&gt;

&lt;p&gt;Without further ado, let's get to it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Lights and Shadows of TDD
&lt;/h2&gt;

&lt;p&gt;Agile practices are highly beneficial for the fast prototyping of software. TDD sits at the core of such practices, providing software with a paramount property: robustness. Writing tests upfront forces developers to think about the expected and exceptional behaviour of the software components they build, enhancing code quality and ensuring the fulfilment of functional requirements.&lt;/p&gt;

&lt;p&gt;While TDD is no silver bullet as one must comply with good practices such as the SOLID principles, it is a powerful practice that &lt;a href="https://qr.ae/pvDzKZ"&gt;enables developers not to be afraid to fix, clean, and adapt their code to functional requirement updates&lt;/a&gt;. And that is all great. However, it is not that easy to effectively apply TDD.&lt;/p&gt;

&lt;p&gt;At the beginning of the construction of any new enterprise application, we (developers) gather several functional requirements. Then, we derive a set of use cases that will satisfy such functional requirements. After that, we develop software components sitting at different layers, from the highest to the lowest, drilling down to the heart of the application i.e., its domain model. That is the definition of the &lt;em&gt;top-down&lt;/em&gt; software development process.&lt;/p&gt;

&lt;p&gt;However, the &lt;em&gt;bottom-up&lt;/em&gt; software development process fits better with TDD. Compared to the top-down alternative, bottom-up is a more pragmatic approach, since it enables us to incrementally cover all levels of indirection starting with the most basic (i.e., the domain model) and gradually moving towards higher layers of abstraction. It allows the production of sounder application code foundations, which in turn makes us gain great confidence in our work. &lt;/p&gt;

&lt;p&gt;To apply TDD in a top-down approach, however, one should first write tests for software components located at the higher layers. Thus, to make tests pass, developers must mock any dependencies to any lower-layer components, since they simply do not exist just yet. The need to create such dependencies is already a problem because mocking lower layer components is not always possible or, in the best case scenario, feels counter-intuitive e.g., imagine yourself having to mock the logic of a domain object for the sake of producing a service component test.&lt;/p&gt;

&lt;p&gt;Furthermore, I personally doubt that it would bring any value at all, as I think that intermediate component validation should always exercise all dependencies except those to external services (e.g., a database), which can be mocked. More importantly, due to the inherent complexity to realise non-trivial functional requirements as code, one does not fully understand the technical implications that some given functional requirements have on the domain model until one starts reasoning about them during the implementation of the domain model.&lt;/p&gt;

&lt;p&gt;Start to write intermediate software components tests may thus not be a good idea, since many of those tests (if not all) are likely to be thrown to the dustbin once the lower layer software artefacts are actually implemented. Furthermore, I have seen software developers (especially junior teammates) giving up and implementing some proof of concept for the use case at hand without writing any validation logic whatsoever. This is using the code-first practice, which defeats the purpose of TDD. Also, without following proper Continuous Delivery practices, there is a high risk of ending up pushing non-validated code to our version control repository.&lt;/p&gt;

&lt;p&gt;So, how could we effectively apply TDD in the production of enterprise applications given a set of functional requirements?&lt;/p&gt;

&lt;h2&gt;
  
  
  Hexagonal Architecture to the Rescue
&lt;/h2&gt;

&lt;p&gt;There is plenty of literature on Hexagonal Architecture on the Internet. I would especially recommend reading the &lt;a href="https://alistair.cockburn.us/hexagonal-architecture/"&gt;white paper&lt;/a&gt; on the topic written by Alistair Cockburn.&lt;/p&gt;

&lt;p&gt;For the purpose of the present article, please allow me to tell you a real-life short story aimed to briefly explain the motivation and main benefits of Hexagonal Architecture: In the many years that I have been developing enterprise applications I have seen many people (myself included) starting new projects focusing on other topics rather than in our real mission. Such a mission consists of providing actual value to the companies we work for. That value is on the domain logic of our applications.&lt;/p&gt;

&lt;p&gt;Paraphrasing Uncle Bob in his book Clean Architecture, everything else is a distraction, an implementation detail that can (and should) be postponed, ideally to the end of development. Examples of implementation details are database technologies, controller logic, or frontend technology. Even the backend framework is an implementation detail that we could pick later in the development process if we really wanted. Hexagonal Architecture, also called &lt;em&gt;Ports and Adapters&lt;/em&gt;, is an architectural pattern aimed to decouple software application core logic from outer implementation details.&lt;/p&gt;

&lt;p&gt;We developers should focus on the core logic of enterprise applications and postpone the implementation of the logic required to communicate with external services. To achieve that goal, all we really need to do is to write some interfaces (so-called &lt;em&gt;ports&lt;/em&gt;) and mock the components (so-called &lt;em&gt;adapters&lt;/em&gt;) that actually communicate with the external services. Thus, adapter implementation can come later in the development process. And the later they come, the better, since all the insights that we gain while we produce the core logic proves really useful during the decision-making of which technologies to pick.&lt;/p&gt;

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

&lt;p&gt;Consider the elements that compose the inner hexagon. Apart from the domain model, there is also a layer of &lt;em&gt;application services&lt;/em&gt;. These software components do not specify any domain logic. Instead, they are simple coordinators of adapter and domain model logic. An application service realises a use case that takes care of a subset of functional requirements for the enterprise application. This is important data to keep in mind for what comes next.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Effectively Use TDD in Hexagonal Architecture-based Enterprise Applications
&lt;/h2&gt;

&lt;p&gt;As I stated earlier, applying TDD is easier when following the bottom-up software development process. However, many of us find it easier to reason about a system design following the top-down approach. And although it seems that we are incurring a conflict of interest, that is fine because we can start designing (i.e., sketching in pseudocode or some UML diagram) our application services top-down without writing a single line of code for them; not until we complete the implementation of the domain model.&lt;/p&gt;

&lt;p&gt;Before we start coding, we could interpret application services as some software design guidelines to perform vertical slices of the enterprise applications we are to build. Each vertical slice represents the whole execution path of a use case, from the action performed by an upstream external service or a user in a UI to any operation executed on a downstream external service. By the time we finish with the design of an application service, we have identified which adapters and domain components we need to implement. Now that we have visibility on the domain model, we can next implement its fundamental components by applying TDD.&lt;/p&gt;

&lt;p&gt;Then, we can implement the application service following the test-first approach, creating a port to any external service adapter and mocking its actual implementation. By the time we are done with the implementation of the application service and the related domain model, we can ascertain that such implementation is valid i.e., likely to be bug-free and matching its functional requirements. &lt;strong&gt;Finally, we can implement the adapter logic, also applying TDD&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This methodology enables fast and gradual implementation of enterprise applications, allowing developers to gain confidence in the validity of all the components they create without throwing any test away. Moreover, it does not impose any restrictions on functional requirement updates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fddgtgsvr6ae1cql2eq55.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fddgtgsvr6ae1cql2eq55.png" alt="TDD-based Enterprise Application Development Flow Diagram" width="800" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This diagram depicts the methodology to write the logic of one use case. Notice that I do not talk about specific test types since this is a pretty controversial subject, although I would recommend following the conventions and terminology used in &lt;a href="https://martinfowler.com/articles/practical-test-pyramid.html"&gt;The Practical Test Pyramid&lt;/a&gt; article.&lt;/p&gt;

&lt;p&gt;The proposed methodology simplifies team task distribution, no matter whether they work alone or in pairs. Some of its steps can be done in parallel e.g., a teammate/pair can build the core logic mocking any reference to an external dependency, whereas another can be working on the development of the integration code with such external dependency, since these two parts are decoupled, thus shortening delivery time. All they need to do is convey some API for the external dependency realised as a port. Both the mock and the actual external dependency need to implement the aforementioned port interface. Similarly, another team/teammate/pair can implement the frontend part for the use case, if that is what the enterprise application demands.&lt;/p&gt;

&lt;p&gt;On another hand, due to its structured nature, communicating the state of development of a concrete use case among peers is easy. When handing over a use case development, the departing entity can simply point the new one to the current application service they were designing or implementing. The new entity then can simply trace anything that has been already created on adapter or domain logic in the code base.&lt;/p&gt;

&lt;p&gt;A final note on implementation details: We could update our domain model to specify some of those details by writing annotations/decorators of the database technology and input data validation resources from the underlying framework that adjusts best to the nature of our application. I would however advise against it, as that would be leaking implementation details into our domain model, which is not the best practice since implementation details and the domain model tend to change for different reasons and frequency. On another hand, as explained by Vaughn Vernon in his book Implementing Domain Driven Design (DDD), Hexagonal Architecture is closely related to DDD. However, you do not need to follow the set of DDD practices and patterns to build complex enterprise applications that are based on Hexagonal Architecture, although I would highly recommend you do. But those decisions, after all, are entirely up to you.&lt;/p&gt;

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

&lt;p&gt;Test-Driven Development is a powerful practice in the construction of robust enterprise applications. TDD is best applied following the bottom-up software development process. However, because developers are used to reasoning about such applications following a top-down approach, applying it in practice is challenging. This article exposes a simple methodology to help developers effectively apply TDD in the development of enterprise applications.&lt;/p&gt;

&lt;p&gt;Cover photo by &lt;a href="https://unsplash.com/ja/@aedrian?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Aedrian&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/cDe4G55k6pE?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>agile</category>
      <category>architecture</category>
      <category>productivity</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
