<?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: Mohammad Jawad (Kasir) Barati</title>
    <description>The latest articles on DEV Community by Mohammad Jawad (Kasir) Barati (@kasir-barati).</description>
    <link>https://dev.to/kasir-barati</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%2F595495%2Fbcaf7914-29aa-4a9b-88fb-ddf3fd9c254c.png</url>
      <title>DEV Community: Mohammad Jawad (Kasir) Barati</title>
      <link>https://dev.to/kasir-barati</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kasir-barati"/>
    <language>en</language>
    <item>
      <title>Write e2e tests for NestJS with testcontainers</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Fri, 28 Mar 2025 18:07:59 +0000</pubDate>
      <link>https://dev.to/kasir-barati/write-e2e-tests-for-nestjs-with-testcontainers-5308</link>
      <guid>https://dev.to/kasir-barati/write-e2e-tests-for-nestjs-with-testcontainers-5308</guid>
      <description>&lt;p&gt;So I was really annoyed last time I was trying to mock and have some tests for my NestJS app. So I decided to try testcontainers once more.&lt;/p&gt;

&lt;p&gt;Last time I was trying to mock BullMQ and it was giving me a hard time, and this time around I managed to get it working.&lt;/p&gt;

&lt;p&gt;Stick around and see how I did it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Support Me
&lt;/h2&gt;

&lt;p&gt;You can support me by giving &lt;a href="https://github.com/kasir-barati/nestjs-materials" rel="noopener noreferrer"&gt;my GitHub repo a star&lt;/a&gt;, so more developers start writing tests. I am a true believer of automated tests and TDD.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;So basically I really do not wanna spy one anything or mock for that matter. But rather I am only interested in knowing that my queue received a message and did its job, e.g. called an external API.&lt;/p&gt;

&lt;p&gt;Actually here I am not gonna test that but if you need to verify that the external API was called I think you can simply have a Wiremock Testcontainer and check it was called.&lt;/p&gt;

&lt;p&gt;I will not cover that case here, at least not now. But what I am interested to show you here is how the e2e test will look 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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TestingModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;INestApplication&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RedisContainer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testcontainers/redis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;supertest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;supertest/types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./../src/app.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AppController (e2e)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;INestApplication&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;beforeAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RedisContainer&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SERVICE_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIS_URI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHostname&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIS_PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPort&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;moduleFixture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestingModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTestingModule&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;AppModule&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;moduleFixture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createNestApplication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/ (GET)&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="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHttpServer&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here I was not trying to use &lt;code&gt;ConfigService&lt;/code&gt;, so I just hacked in my way into the &lt;code&gt;process.env&lt;/code&gt;. But feel free to check &lt;a href="https://github.com/kasir-barati/nestjs-materials/blob/main/typeorm/apps/botprobe-nest/src/app/configs/app.config.ts" rel="noopener noreferrer"&gt;my repo&lt;/a&gt; for a more mature way of dealing with env variables.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  GitHub Repo
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kasir-barati" rel="noopener noreferrer"&gt;
        kasir-barati
      &lt;/a&gt; / &lt;a href="https://github.com/kasir-barati/nestjs-materials" rel="noopener noreferrer"&gt;
        nestjs-materials
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      NestJS tips, tricks, Notes, Things which are not in doc and I used to figure them out and use them
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-alert markdown-alert-important"&gt;
&lt;p class="markdown-alert-title"&gt;Important&lt;/p&gt;
&lt;p&gt;Keep this file synchronized with &lt;a href="https://github.com/kasir-barati/nestjs-materials/../index.md" rel="noopener noreferrer"&gt;&lt;code&gt;index.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Table of contents&lt;/h1&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials/../docs/dto.md" rel="noopener noreferrer"&gt;DTO&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials/../docs/dynamic-modules/README.md" rel="noopener noreferrer"&gt;Dynamic modules&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials/../docs/dependency-injection.md" rel="noopener noreferrer"&gt;Dependency Injection&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials/../microservices/README.md" rel="noopener noreferrer"&gt;Microservices&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials/../docs/grpc/README.md" rel="noopener noreferrer"&gt;gRPC&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials/../docs/grpc/protobuf.md" rel="noopener noreferrer"&gt;Protobuf&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/nestjs-materials/../docs/debugging/README.md" rel="noopener noreferrer"&gt;How to debug your code and flaky tests&lt;/a&gt;.

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials/../docker/vscode-dev-mode/README.md" rel="noopener noreferrer"&gt;A Crude Debug Mode For a Dockerized NestJS App&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/nestjs-materials/../docs/designing-restful-api/README.md" rel="noopener noreferrer"&gt;Designing and versioning RESTful APIs&lt;/a&gt;.

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials/../docs/designing-restful-api/pagination.md" rel="noopener noreferrer"&gt;Pagination&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/nestjs-materials/../docs/mockserver/README.md" rel="noopener noreferrer"&gt;MockServer and mocking 3rd-party HTTP/S calls&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/nestjs-materials/../docs/kafka/README.md" rel="noopener noreferrer"&gt;Kafka intro&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;RabbitMQ:

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials/../docs/rabbitmq/README.md" rel="noopener noreferrer"&gt;Intro&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/bugs/tree/nestjs-rabbitmq-batch-processing-messages" rel="noopener noreferrer"&gt;Batch processing and requeueing the failed messages and not the whole batch&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/bugs/tree/golevelup-nestjs-rabbitmq-default-value-for-prefetch" rel="noopener noreferrer"&gt;Default value for prefetch count in &lt;code&gt;@golevelup/nestjs-rabbitmq&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials/../docs/rabbitmq/share-rabbitmq-connection-with-dynamic-module/README.md" rel="noopener noreferrer"&gt;Share a RabbitMQ connection with a Dynamic modules&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials/../docs/rabbitmq/dead-letter-queue/README.md" rel="noopener noreferrer"&gt;How to configure a Dead letter queue (DLQ) in NestJS&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials/../docs/rabbitmq/updating-queue.md" rel="noopener noreferrer"&gt;Updating a queue&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials/../docs/rabbitmq/classic-vs-quorum.md" rel="noopener noreferrer"&gt;Classic VS Quorum queues&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/kasir-barati/nestjs-materials/../docs/nestjs-query/README.md" rel="noopener noreferrer"&gt;NestJS and GraphQL with &lt;code&gt;nestjs-query&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/kasir-barati/nestjs-materials/../mongoose" rel="noopener noreferrer"&gt;Mongoose&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/nestjs-materials/../decorator" rel="noopener noreferrer"&gt;Custom decorators&lt;/a&gt;.&lt;/li&gt;

&lt;/ul&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kasir-barati/nestjs-materials" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;





&lt;p&gt;Instagram: &lt;a href="https://www.instagram.com/node.js.developers.kh/" rel="noopener noreferrer"&gt;https://www.instagram.com/node.js.developers.kh/&lt;/a&gt;&lt;br&gt;
Facebook: &lt;a href="https://www.facebook.com/kasirbarati" rel="noopener noreferrer"&gt;https://www.facebook.com/kasirbarati&lt;/a&gt;&lt;br&gt;
X: &lt;a href="https://x.com/kasir_barati" rel="noopener noreferrer"&gt;https://x.com/kasir_barati&lt;/a&gt;&lt;br&gt;
YouTube: &lt;a href="https://www.youtube.com/@kasir-barati" rel="noopener noreferrer"&gt;https://www.youtube.com/@kasir-barati&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/kasir-barati/" rel="noopener noreferrer"&gt;https://github.com/kasir-barati/&lt;/a&gt;&lt;br&gt;
Dev.to: &lt;a href="https://dev.to/kasir-barati"&gt;https://dev.to/kasir-barati&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://linkedin.com/in/kasir-barati" rel="noopener noreferrer"&gt;https://linkedin.com/in/kasir-barati&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>tdd</category>
      <category>e2e</category>
      <category>nestjs</category>
    </item>
    <item>
      <title>GraphQL + NestJS + Interfaces + Unions</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Sat, 22 Mar 2025 18:01:10 +0000</pubDate>
      <link>https://dev.to/kasir-barati/graphql-nestjs-interfaces-unions-3794</link>
      <guid>https://dev.to/kasir-barati/graphql-nestjs-interfaces-unions-3794</guid>
      <description>&lt;p&gt;So guys I was really confused by the NestJS's doc as to ho you can have an API which can be invoked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;robots&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HumanoidRobot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ScaraRobot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;axes&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So in others words I wanted to not repeat myself by having an interface and I needed to also prevent any fields from other types leaking to another one.&lt;/p&gt;



&lt;p&gt;The solution was simple, first I had to define my &lt;code&gt;RobotInterface&lt;/code&gt;, &lt;code&gt;HumanoidRobot&lt;/code&gt; object type and &lt;code&gt;ScaraRobot&lt;/code&gt;:&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;app/types/robot-interface.type.ts&lt;/code&gt;
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Field&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="nx"&gt;InterfaceType&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/graphql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HumanoidRobot&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./humanoid.type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ScaraRobot&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./scara.type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;InterfaceType&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;'Common fields, available for all robots',&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="na"&gt;resolveType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;height&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;value&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;HumanoidRobot&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;ScaraRobot&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;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RobotInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Field&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;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;'ID of the robot' })&lt;/span&gt;&lt;span class="dl"&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Field&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;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;'Name of the robot' })&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="na"&gt;name&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="nd"&gt;Field&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;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;'The COLLADA image of the robot',&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="na"&gt;colladaImage&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="nd"&gt;Field&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;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;'Description of the robot' })&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Field&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;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;'Model number of the robot' })&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="na"&gt;modelNumber&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;app/types/scara.type.ts&lt;/code&gt;
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ObjectType&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/graphql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RobotInterface&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./robot-interface.type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ObjectType&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;implements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;RobotInterface&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Scara robot, specialized for tasks requiring high precision &amp;amp; speed&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ScaraRobot&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;RobotInterface&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;name&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;colladaImage&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;modelNumber&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="nd"&gt;Field&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;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;'Number of axes',&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;axes&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="nd"&gt;Field&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;Float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;'Payload capacity in kg',&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And something similar to this for the &lt;code&gt;HumanoidRobot&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Caution&lt;/p&gt;

&lt;p&gt;the &lt;code&gt;implements&lt;/code&gt; option should be a callback function and not a simple &lt;code&gt;implements: [RobotInterface]&lt;/code&gt;. This in fact wasted my precious 2 hours. So it should be &lt;code&gt;implements: () =&amp;gt; [RobotInterface]&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p&gt;And note that the &lt;code&gt;resolveType&lt;/code&gt; will help your NestJS app to decide which type it should use, TBH I saw in a lot of places people use enums. In other word they add an extra field to the &lt;code&gt;RobotInterface&lt;/code&gt; and call it type and decide based on that field. I guess that would be easier to have compare to relying on the presence of a field.&lt;/p&gt;

&lt;p&gt;So feel free to do that instead of this, it would look like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;InterfaceType&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Common fields, available for all robots&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;resolveType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;RobotType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HUMANOID&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;HumanoidRobot&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;ScaraRobot&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;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RobotInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Field&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;RobotType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Type of the robot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RobotType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And of course you need to &lt;a href="https://docs.nestjs.com/graphql/unions-and-enums" rel="noopener noreferrer"&gt;register the enum type first&lt;/a&gt;. &lt;/p&gt;



&lt;p&gt;Finally we need a resolver:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;RobotInterface&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Get all robots&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nf"&gt;robots&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RobotInterface&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;appService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRobots&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h1&gt;
  
  
  Unions
&lt;/h1&gt;

&lt;p&gt;This is not really any different that interfaces, just use the &lt;code&gt;createUnionType&lt;/code&gt; helper function and pass your classes, then specify on which type it should return what:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createUnionType&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/graphql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HumanoidRobot&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./humanoid.type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ScaraRobot&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./scara.type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UnionOfRobots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createUnionType&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UnionOfRobots&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Union of robots fields&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;HumanoidRobot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ScaraRobot&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;resolveType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;height&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;value&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;HumanoidRobot&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;ScaraRobot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And then specify that as the return type of your query, or mutation.&lt;/p&gt;


&lt;h2&gt;
  
  
  Support Me
&lt;/h2&gt;

&lt;p&gt;You can support me by liking this post, reading my other posts and giving my repo a star on GitHub.&lt;/p&gt;



&lt;p&gt;As simple as that. Need the code itself? Do not worry I've got you covered:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kasir-barati" rel="noopener noreferrer"&gt;
        kasir-barati
      &lt;/a&gt; / &lt;a href="https://github.com/kasir-barati/graphql-js-ts" rel="noopener noreferrer"&gt;
        graphql-js-ts
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Where you can learn all about GraphQL and its intricacies
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-alert markdown-alert-caution"&gt;
&lt;p class="markdown-alert-title"&gt;Caution&lt;/p&gt;
&lt;p&gt;Keep this file in sync with &lt;a href="https://github.com/kasir-barati/graphql-js-ts../index.md" rel="noopener noreferrer"&gt;&lt;code&gt;index.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;GraphQL&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-alert markdown-alert-tip"&gt;
&lt;p class="markdown-alert-title"&gt;Tip&lt;/p&gt;
&lt;p&gt;Just for those curious minds who always jump from one branch to another like mine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/hasura.md" rel="noopener noreferrer"&gt;Hasura&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.apollographql.com/blog/graphql-vs-rest" rel="nofollow noopener noreferrer"&gt;GraphQL VS REST&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/testing-graphql.md" rel="noopener noreferrer"&gt;Testing GraphQL API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;p&gt;You can find a good definition usually in &lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/glossary.md" rel="noopener noreferrer"&gt;glossary&lt;/a&gt;.&lt;/p&gt;


&lt;ol&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/intro.md" rel="noopener noreferrer"&gt;Intro&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/data-types.md" rel="noopener noreferrer"&gt;Data types&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;A simple todo app written with GraphQL + ReactJS + Relay

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/graphql-js-ts../apps/todo-backend/README.md" rel="noopener noreferrer"&gt;Backend&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/graphql-js-ts" rel="noopener noreferrer"&gt;Frontend&lt;/a&gt; TK.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/queries-and-mutations.md" rel="noopener noreferrer"&gt;Queries and mutations in depth&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/graphql-query-language-breakdown.md" rel="noopener noreferrer"&gt;Let's breakdown the query language a bit more&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/function-provided-by-graphql.md" rel="noopener noreferrer"&gt;Functions provided by &lt;code&gt;graphql&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/documentation.md" rel="noopener noreferrer"&gt;Document your GraphQL service API&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/graphql-req-lifecycle.md" rel="noopener noreferrer"&gt;GraphQL request lifecycle&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/common-errors.md" rel="noopener noreferrer"&gt;Common validation errors&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/execution-from-inside.md" rel="noopener noreferrer"&gt;Execution from inside, resolver's args, AST, ...&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/code-first.md" rel="noopener noreferrer"&gt;Code-first approach&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/auth.md" rel="noopener noreferrer"&gt;Auth&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/introspection.md" rel="noopener noreferrer"&gt;How to query information about a GraphQL schema&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/improve-dev-exp/index.md" rel="noopener noreferrer"&gt;Improve developer experience&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/improve-dev-exp/ioc.md" rel="noopener noreferrer"&gt;IoC -- Inversion of Control principle&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/improve-dev-exp/use-schema-graphql-files.md" rel="noopener noreferrer"&gt;Use a &lt;code&gt;schema.graphql&lt;/code&gt; file&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/improve-dev-exp/strongly-typed.md" rel="noopener noreferrer"&gt;Strongly typed resolvers, context, ...&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/improve-dev-exp/filtering-using-prisma-nestjs-graphql.md" rel="noopener noreferrer"&gt;Filtering using &lt;code&gt;prisma-nestjs-graphql&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/security.md" rel="noopener noreferrer"&gt;Security in GraphQL&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/nestjs.md" rel="noopener noreferrer"&gt;NestJS&lt;/a&gt;

&lt;ul&gt;&lt;li&gt;…&lt;/li&gt;&lt;/ul&gt;


&lt;/li&gt;

&lt;/ol&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kasir-barati/graphql-js-ts" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;blockquote&gt;
&lt;p&gt;Note&lt;/p&gt;

&lt;p&gt;This is a monorepo, so I have tons of other apps, but the one you're interested in at the moment is &lt;code&gt;apps/interfaces-unions&lt;/code&gt;. BTW If you like to learn how to write e2e tests for you NestJS app look at the &lt;code&gt;apps/interfaces-unions-e2e&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Instagram: &lt;a href="https://www.instagram.com/node.js.developers.kh/" rel="noopener noreferrer"&gt;https://www.instagram.com/node.js.developers.kh/&lt;/a&gt;&lt;br&gt;
Facebook: &lt;a href="https://www.facebook.com/kasirbarati" rel="noopener noreferrer"&gt;https://www.facebook.com/kasirbarati&lt;/a&gt;&lt;br&gt;
X: &lt;a href="https://x.com/kasir_barati" rel="noopener noreferrer"&gt;https://x.com/kasir_barati&lt;/a&gt;&lt;br&gt;
YouTube: &lt;a href="https://www.youtube.com/@kasir-barati" rel="noopener noreferrer"&gt;https://www.youtube.com/@kasir-barati&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/kasir-barati/" rel="noopener noreferrer"&gt;https://github.com/kasir-barati/&lt;/a&gt;&lt;br&gt;
Dev.to: &lt;a href="https://dev.to/kasir-barati"&gt;https://dev.to/kasir-barati&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://linkedin.com/in/kasir-barati" rel="noopener noreferrer"&gt;https://linkedin.com/in/kasir-barati&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>nestjs</category>
      <category>javascript</category>
      <category>graphql</category>
    </item>
    <item>
      <title>NestJS + AWS S3 + Multipart file upload + gRPC + e2e testing</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Sun, 09 Mar 2025 13:35:33 +0000</pubDate>
      <link>https://dev.to/kasir-barati/nestjs-aws-s3-multipart-file-upload-grpc-e2e-testing-550e</link>
      <guid>https://dev.to/kasir-barati/nestjs-aws-s3-multipart-file-upload-grpc-e2e-testing-550e</guid>
      <description>&lt;p&gt;So I was wondering how I can upload a file to AWS S3 over gRPC with a NodeJS/NestJS backend app. And ever since I was introduced to the concept of TDD I've been trying to write unit tests and e2e tests, thus I tried to automate my application's tests.&lt;/p&gt;

&lt;p&gt;Although this is still far from being perfect but at least it is a good starting point for many of you guys.&lt;/p&gt;

&lt;h2&gt;
  
  
  How To Support Me?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;To support me, please give this post a like, and give the repo I have for this project a star on GitHub&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Read &lt;a href="https://dev.to/kasir-barati/aws-s3-multipart-file-upload-surprise-bills-4059"&gt;this article&lt;/a&gt; of mine.&lt;/li&gt;
&lt;li&gt;Read &lt;a href="https://github.com/kasir-barati/cloud/blob/main/aws/S3/multipart-file-upload.md" rel="noopener noreferrer"&gt;Multipart File Upload in AWS S3&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Read the &lt;a href="https://github.com/kasir-barati/nestjs-materials/tree/main/microservices/grpc#file-upload" rel="noopener noreferrer"&gt;&lt;code&gt;README.md&lt;/code&gt;&lt;/a&gt; to know about the design decisions I made.&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kasir-barati" rel="noopener noreferrer"&gt;
        kasir-barati
      &lt;/a&gt; / &lt;a href="https://github.com/kasir-barati/nestjs-materials" rel="noopener noreferrer"&gt;
        nestjs-materials
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      NestJS tips, tricks, Notes, Things which are not in doc and I used to figure them out and use them
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-alert markdown-alert-important"&gt;
&lt;p class="markdown-alert-title"&gt;Important&lt;/p&gt;
&lt;p&gt;Keep this file synchronized with &lt;a href="https://github.com/kasir-barati/nestjs-materials../index.md" rel="noopener noreferrer"&gt;&lt;code&gt;index.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;nestjs-materials&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;NestJS tips, tricks, Notes, Things which are not in doc and I used to figure them out and use them&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials../microservices/README.md" rel="noopener noreferrer"&gt;Microservices&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials../docs/grpc/README.md" rel="noopener noreferrer"&gt;gRPC&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials../docs/grpc/protobuf.md" rel="noopener noreferrer"&gt;Protobuf&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials../docs/debugging/README.md" rel="noopener noreferrer"&gt;How to debug your code and flaky tests&lt;/a&gt;.
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials../docker/vscode-dev-mode/README.md" rel="noopener noreferrer"&gt;A Crude Debug Mode For a Dockerized NestJS App&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials../docs/designing-restful-api/README.md" rel="noopener noreferrer"&gt;Designing and versioning RESTful APIs&lt;/a&gt;.
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials../docs/designing-restful-api/pagination.md" rel="noopener noreferrer"&gt;Pagination&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials../docs/mockserver/README.md" rel="noopener noreferrer"&gt;MockServer and mocking 3rd-party HTTP/S calls&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials../docs/kafka/README.md" rel="noopener noreferrer"&gt;Kafka intro&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials../docs/rabbitmq/README.md" rel="noopener noreferrer"&gt;RabbitMQ intro&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kasir-barati/nestjs-materials../docs/nestjs-query/README.md" rel="noopener noreferrer"&gt;NestJS and GraphQL with &lt;code&gt;nestjs-query&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kasir-barati/nestjs-materials" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;





&lt;p&gt;Instagram: &lt;a href="https://www.instagram.com/node.js.developers.kh/" rel="noopener noreferrer"&gt;https://www.instagram.com/node.js.developers.kh/&lt;/a&gt;&lt;br&gt;
Facebook: &lt;a href="https://www.facebook.com/kasirbarati" rel="noopener noreferrer"&gt;https://www.facebook.com/kasirbarati&lt;/a&gt;&lt;br&gt;
X: &lt;a href="https://x.com/kasir_barati" rel="noopener noreferrer"&gt;https://x.com/kasir_barati&lt;/a&gt;&lt;br&gt;
YouTube: &lt;a href="https://www.youtube.com/@kasir-barati" rel="noopener noreferrer"&gt;https://www.youtube.com/@kasir-barati&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/kasir-barati/" rel="noopener noreferrer"&gt;https://github.com/kasir-barati/&lt;/a&gt;&lt;br&gt;
Dev.to: &lt;a href="https://dev.to/kasir-barati"&gt;https://dev.to/kasir-barati&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://linkedin.com/in/kasir-barati" rel="noopener noreferrer"&gt;https://linkedin.com/in/kasir-barati&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nestjs</category>
      <category>grpc</category>
      <category>s3</category>
      <category>testing</category>
    </item>
    <item>
      <title>Get a list of endpoints in your NestJS app</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Fri, 07 Mar 2025 12:28:35 +0000</pubDate>
      <link>https://dev.to/kasir-barati/get-a-list-of-endpoints-in-your-nestjs-app-2gfd</link>
      <guid>https://dev.to/kasir-barati/get-a-list-of-endpoints-in-your-nestjs-app-2gfd</guid>
      <description>&lt;p&gt;So here is how I get a list of all defined HTTP endpoints in my E2E test in a NestJS app with their default configuration and setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TestingModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SomeModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./some/where/some.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;moduleFixture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestingModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTestingModule&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;SomeModule&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;moduleFixture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createNestApplication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHttpServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&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;This is mostly useful when I am banging my head against a brick wall as to why supertest says an endpoint does not exists (the infamous 404 error). So feel free to use this hack whenever you stock in the same spot :).&lt;/p&gt;

&lt;p&gt;BTW feel free to like this post, subscribe and comment.&lt;/p&gt;




&lt;p&gt;Instagram: &lt;a href="https://www.instagram.com/node.js.developers.kh/" rel="noopener noreferrer"&gt;https://www.instagram.com/node.js.developers.kh/&lt;/a&gt;&lt;br&gt;
Facebook: &lt;a href="https://www.facebook.com/kasirbarati" rel="noopener noreferrer"&gt;https://www.facebook.com/kasirbarati&lt;/a&gt;&lt;br&gt;
X: &lt;a href="https://x.com/kasir_barati" rel="noopener noreferrer"&gt;https://x.com/kasir_barati&lt;/a&gt;&lt;br&gt;
YouTube: &lt;a href="https://www.youtube.com/@kasir-barati" rel="noopener noreferrer"&gt;https://www.youtube.com/@kasir-barati&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/kasir-barati/" rel="noopener noreferrer"&gt;https://github.com/kasir-barati/&lt;/a&gt;&lt;br&gt;
Dev.to: &lt;a href="https://dev.to/kasir-barati"&gt;https://dev.to/kasir-barati&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://linkedin.com/in/kasir-barati" rel="noopener noreferrer"&gt;https://linkedin.com/in/kasir-barati&lt;/a&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>nestjs</category>
      <category>node</category>
      <category>restapi</category>
    </item>
    <item>
      <title>AWS S3 - Multipart file upload - Surprise Bills</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Sat, 15 Feb 2025 06:26:16 +0000</pubDate>
      <link>https://dev.to/kasir-barati/aws-s3-multipart-file-upload-surprise-bills-4059</link>
      <guid>https://dev.to/kasir-barati/aws-s3-multipart-file-upload-surprise-bills-4059</guid>
      <description>&lt;p&gt;It is super easy to loss sight of AWS's hidden costs or at least somewhat hard to find unless you're a meticulous person who loves reading docs and ain't under deadline pressure where you cannot find the time to even scratch your back 😂.&lt;/p&gt;

&lt;p&gt;Back to the topic of cost management, so assume you're using the multipart file upload and if you're upload was busted in the middle you're not aborting the whole thing. Here is where things gets interesting, AWS will store those chunk of data for you forever, unless you have configured a life cycle rule or have called their &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html" rel="noopener noreferrer"&gt;&lt;code&gt;AbortMultipartUpload&lt;/code&gt;&lt;/a&gt; API.&lt;/p&gt;

&lt;p&gt;For more details check out my GitHub repo where you can find other places where you might be incurring cost without knowing it. BTW if this was helpful to you consider &lt;strong&gt;giving my repo a star&lt;/strong&gt; so more people can reach it and learn about these aspects of cloud.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kasir-barati" rel="noopener noreferrer"&gt;
        kasir-barati
      &lt;/a&gt; / &lt;a href="https://github.com/kasir-barati/cloud" rel="noopener noreferrer"&gt;
        cloud
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      It was my endeavour to build a wrapper around Docker and develop a RESTful API. In order to serve Platform as a Service. But now it's a place to learn more about cloud and put things into practice, of course things that are related to this topic.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-alert markdown-alert-important"&gt;
&lt;p class="markdown-alert-title"&gt;Important&lt;/p&gt;
&lt;p&gt;Keep this file content in sync with &lt;a href="https://github.com/kasir-barati/cloud../index.md" rel="noopener noreferrer"&gt;&lt;code&gt;index.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Cloud&lt;/h1&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;I love to hear your thoughts about the things that I am doing here. So reach out. Or better yet, formulate your thoughts in a GH issue.&lt;/li&gt;
&lt;li&gt;Most of the things I am putting in this repo are my own original creation, although I'm not reinventing the wheel when it is out there. So I might have taken some parts of other's creation and modified them to suit my needs. So credits goes still to the original creator of those contents.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-alert markdown-alert-note"&gt;
&lt;p class="markdown-alert-title"&gt;Note&lt;/p&gt;
&lt;p&gt;Initial codebase: this repo was intended to be a professional RESTful API in time, but it didn't come to fruition. So now you can see my endeavour &lt;a href="https://github.com/kasir-barati/paas-system/tree/initial-branch" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Be Careful With Your Bills&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Learn about some common pitfalls when it comes to cloud and its bills &lt;a href="https://github.com/kasir-barati/cloud../no-surprise-bill/README.md" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Handwritings&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;I first started by jotting down on…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kasir-barati/cloud" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;p&gt;BTW you can find me here as well:&lt;/p&gt;

&lt;p&gt;Instagram: &lt;a href="https://www.instagram.com/node.js.developers.kh/" rel="noopener noreferrer"&gt;https://www.instagram.com/node.js.developers.kh/&lt;/a&gt;&lt;br&gt;
Facebook: &lt;a href="https://www.facebook.com/kasirbarati" rel="noopener noreferrer"&gt;https://www.facebook.com/kasirbarati&lt;/a&gt;&lt;br&gt;
X: &lt;a href="https://x.com/kasir_barati" rel="noopener noreferrer"&gt;https://x.com/kasir_barati&lt;/a&gt;&lt;br&gt;
YouTube: &lt;a href="https://www.youtube.com/@kasir-barati" rel="noopener noreferrer"&gt;https://www.youtube.com/@kasir-barati&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/kasir-barati/" rel="noopener noreferrer"&gt;https://github.com/kasir-barati/&lt;/a&gt;&lt;br&gt;
Dev.to: &lt;a href="https://dev.to/kasir-barati"&gt;https://dev.to/kasir-barati&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://linkedin.com/in/kasir-barati" rel="noopener noreferrer"&gt;https://linkedin.com/in/kasir-barati&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>s3</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>NestJS + gRPC + step by step guide + e2e tests</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Sun, 02 Feb 2025 04:13:35 +0000</pubDate>
      <link>https://dev.to/kasir-barati/nestjs-grpc-step-by-step-guide-e2e-tests-1cb1</link>
      <guid>https://dev.to/kasir-barati/nestjs-grpc-step-by-step-guide-e2e-tests-1cb1</guid>
      <description>&lt;p&gt;What is RPC and how you can use it in NestJS is the question I had in mind to answer in this post. Sit tight for a short, concise, and precise intro to this world:&lt;/p&gt;

&lt;p&gt;So RPC,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stands for Remote Procedure Call.&lt;/li&gt;
&lt;li&gt;It's a communication mechanism.&lt;/li&gt;
&lt;li&gt;It's almost the same as though we have access to the methods/function defined in another program.&lt;/li&gt;
&lt;li&gt;Can be used for inter-service communications.&lt;/li&gt;
&lt;li&gt;Supper efficient.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpk27zccm7461wb0cv9uf.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%2Fpk27zccm7461wb0cv9uf.png" alt="A simple diagram showing how a NestJS app might be calling and RPC in a Python app" width="800" height="554"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[!CAUTION]&lt;/p&gt;

&lt;p&gt;This is still a network call. So do not call it like your codes who are living in the same codebase.&lt;/p&gt;

&lt;p&gt;[!NOTE]&lt;/p&gt;

&lt;p&gt;We can use any application level protocol for sending requests and receiving responses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TCP: HTTP1, HTTP2.&lt;/li&gt;
&lt;li&gt;UDP.&lt;/li&gt;
&lt;li&gt;Websockets.&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means that it is like GraphQL transport layer agnostic. You can use whatever you like.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  gRPC
&lt;/h2&gt;

&lt;p&gt;Now let's demystify the gRPC. It's:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An open-source rewrite of RPC used by Google.&lt;/li&gt;
&lt;li&gt;Why gRPC?

&lt;ol&gt;
&lt;li&gt;It uses only HTTP2 as its transport layer.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials/blob/main/docs/grpc/protobuf.md" rel="noopener noreferrer"&gt;Protocol buffer&lt;/a&gt; as our data exchange format.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;No browser support yet, but a good thing to have for inter-service communication in a microservice architecture.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  NestJS
&lt;/h2&gt;

&lt;p&gt;I love NestJS and how good it is at giving you're code more structure. So here is how you can get up to speed with it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Follow &lt;a href="https://docs.nestjs.com/microservices/grpc" rel="noopener noreferrer"&gt;the official documentation&lt;/a&gt; opn how to bootstrap a NestJS app + gRPC.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   pnpx create-nx-workspace grpc &lt;span class="nt"&gt;--preset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nest &lt;span class="nt"&gt;--appName&lt;/span&gt; nestjs-client &lt;span class="nt"&gt;--bundler&lt;/span&gt; esbuild &lt;span class="nt"&gt;--packageManager&lt;/span&gt; pnpm &lt;span class="nt"&gt;--nxCloud&lt;/span&gt; skip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;I also love perfectionist for a good reason and that is the tidiness it gives you for little conf, so I highly recommend you take a look at it in their &lt;a href="https://perfectionist.dev/guide/getting-started" rel="noopener noreferrer"&gt;official doc&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Or if you're looking for something on how to get up to speed I guess &lt;a href="https://github.com/kasir-barati/docker/commit/6855598149c21c985387fce674a4d1ce5f87ca5f" rel="noopener noreferrer"&gt;this commit&lt;/a&gt; can be a real quick intro to how to use it. BTW I appreciate it if you give my repo a star in case it was helpful 🙂.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   nx run-many &lt;span class="nt"&gt;-t&lt;/span&gt; lint &lt;span class="nt"&gt;--fix&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Write you're protobuf file like what I did &lt;a href="//../../microservices/grpc/apps/nestjs-client/src/assets/user.proto"&gt;here at &lt;code&gt;user.proto&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Use the &lt;a href="https://github.com/stephenh/ts-proto" rel="noopener noreferrer"&gt;&lt;code&gt;ts-proto&lt;/code&gt;&lt;/a&gt; to auto generate the interfaces and decorators for your gRPC controller.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"grpc:gen"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_opt=fileSuffix=.interface --ts_proto_opt=nestJs=true --ts_proto_opt=addNestjsRestParameter=true --ts_proto_out={projectRoot}/src/assets/interfaces -I {projectRoot}/src/assets/ {projectRoot}/src/assets/*.proto"&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;For the complete solution look at &lt;a href="https://github.com/kasir-barati/nestjs-materials/blob/main/microservices/grpc/apps/nestjs-client/project.json" rel="noopener noreferrer"&gt;this&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Now just run the &lt;code&gt;npm run grpc:gen&lt;/code&gt; or if you're using Nx just run &lt;code&gt;nx grpc:gen projectName&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Congrats, you have your types and decorators. So let's &lt;a href="https://github.com/kasir-barati/nestjs-materials/blob/main/microservices/grpc/apps/nestjs-client/src/user/user.grpc-controller.ts" rel="noopener noreferrer"&gt;put them into use&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;[!TIP]&lt;/p&gt;

&lt;p&gt;For a complete example look at the &lt;a href="https://github.com/kasir-barati/nestjs-materials/tree/main/microservices/grpc" rel="noopener noreferrer"&gt;&lt;code&gt;nestjs-client&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Ref
&lt;/h2&gt;

&lt;p&gt;BTW you can find a working example in this repo too, so if this post was useful to you consider sharing it, giving my repo a star and this post a like.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kasir-barati" rel="noopener noreferrer"&gt;
        kasir-barati
      &lt;/a&gt; / &lt;a href="https://github.com/kasir-barati/nestjs-materials" rel="noopener noreferrer"&gt;
        nestjs-materials
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      NestJS tips, tricks, Notes, Things which are not in doc and I used to figure them out and use them
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-alert markdown-alert-important"&gt;
&lt;p class="markdown-alert-title"&gt;Important&lt;/p&gt;
&lt;p&gt;Keep this file synchronized with &lt;a href="https://github.com/kasir-barati/nestjs-materials../index.md" rel="noopener noreferrer"&gt;&lt;code&gt;index.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;nestjs-materials&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;NestJS tips, tricks, Notes, Things which are not in doc and I used to figure them out and use them&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials../microservices/README.md" rel="noopener noreferrer"&gt;Microservices&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials../docs/grpc/README.md" rel="noopener noreferrer"&gt;gRPC&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials../docs/grpc/protobuf.md" rel="noopener noreferrer"&gt;Protobuf&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/nestjs-materials../docs/debugging/README.md" rel="noopener noreferrer"&gt;How to debug your code and flaky tests&lt;/a&gt;.

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials../docker/vscode-dev-mode/README.md" rel="noopener noreferrer"&gt;A Crude Debug Mode For a Dockerized NestJS App&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/nestjs-materials../docs/designing-restful-api/README.md" rel="noopener noreferrer"&gt;Designing and versioning RESTful APIs&lt;/a&gt;.

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/nestjs-materials../docs/designing-restful-api/pagination.md" rel="noopener noreferrer"&gt;Pagination&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/nestjs-materials../docs/mockserver/README.md" rel="noopener noreferrer"&gt;MockServer and mocking 3rd-party HTTP/S calls&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/nestjs-materials../docs/kafka/README.md" rel="noopener noreferrer"&gt;Kafka intro&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/nestjs-materials../docs/rabbitmq/README.md" rel="noopener noreferrer"&gt;RabbitMQ intro&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/kasir-barati/nestjs-materials../docs/nestjs-query/README.md" rel="noopener noreferrer"&gt;NestJS and GraphQL with &lt;code&gt;nestjs-query&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kasir-barati/nestjs-materials" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;





&lt;p&gt;Instagram: &lt;a href="https://www.instagram.com/node.js.developers.kh/" rel="noopener noreferrer"&gt;https://www.instagram.com/node.js.developers.kh/&lt;/a&gt;&lt;br&gt;
Facebook: &lt;a href="https://www.facebook.com/kasirbarati" rel="noopener noreferrer"&gt;https://www.facebook.com/kasirbarati&lt;/a&gt;&lt;br&gt;
X: &lt;a href="https://x.com/kasir_barati" rel="noopener noreferrer"&gt;https://x.com/kasir_barati&lt;/a&gt;&lt;br&gt;
YouTube: &lt;a href="https://www.youtube.com/@kasir-barati" rel="noopener noreferrer"&gt;https://www.youtube.com/@kasir-barati&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/kasir-barati/" rel="noopener noreferrer"&gt;https://github.com/kasir-barati/&lt;/a&gt;&lt;br&gt;
Dev.to: &lt;a href="https://dev.to/kasir-barati"&gt;https://dev.to/kasir-barati&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://linkedin.com/in/kasir-barati" rel="noopener noreferrer"&gt;https://linkedin.com/in/kasir-barati&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>When E2E Tests In NestJS Gives Me a Headache</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Fri, 24 Jan 2025 09:30:25 +0000</pubDate>
      <link>https://dev.to/kasir-barati/when-e2e-tests-in-nestjs-gives-me-a-headache-59ed</link>
      <guid>https://dev.to/kasir-barati/when-e2e-tests-in-nestjs-gives-me-a-headache-59ed</guid>
      <description>&lt;p&gt;Testing can be frustrating, especially when we do not have a well documented library/framework from the perspective of writing tests. E.g. I was banging my head against brick wall as to why my E2E test was failing and it turns out that &lt;a href="https://github.com/nestjs/bull/blob/57c15580e54ddd50c4c50c0e972cc9b57710025a/packages/bull/lib/decorators/processor.decorator.ts#L19" rel="noopener noreferrer"&gt;NestJS's &lt;code&gt;@Processor&lt;/code&gt;&lt;/a&gt; decorator is doing some sort of magic.&lt;/p&gt;

&lt;p&gt;Thus my test was failing. I tried different approaches but none worked:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tried to mock the whole thing with &lt;a href="https://www.npmjs.com/package/ioredis-mock" rel="noopener noreferrer"&gt;&lt;code&gt;ioredis-mock&lt;/code&gt;&lt;/a&gt;. Nope it was still failing:&lt;/li&gt;
&lt;li&gt;I tried &lt;a href="https://testcontainers.com/" rel="noopener noreferrer"&gt;Testcontainers&lt;/a&gt; but still I was getting an error.&lt;/li&gt;
&lt;li&gt;I had a real redis instance running and it was still not passing.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  So What was My Issue When I Tried to Mock the Whole Thing
&lt;/h2&gt;

&lt;p&gt;First I tried to write a code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getQueueToken&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/bullmq&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;INestApplication&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TestingModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;supertest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../src/app.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mockBullMqService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./bullmq.mock&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AppController (e2e)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;INestApplication&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;beforeAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;moduleFixture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TestingModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTestingModule&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;AppModule&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;overrideProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getQueueToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_QUEUE_NAME&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;process&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;moduleFixture&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createNestApplication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;afterAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/ (GET)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHttpServer&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/cart&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Add more tests here&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it was not working because in my &lt;a href="https://github.com/kasir-barati/bugs/blob/5f83dc3a68a9d6c14cb1f12a5eca1f689c62b84d/src/user/audio.consumer.ts" rel="noopener noreferrer"&gt;&lt;code&gt;src/user/audio.consumer.ts&lt;/code&gt;&lt;/a&gt; I had used &lt;code&gt;@Processor&lt;/code&gt; decorator. And this is not documented anywhere. Yes, it sucks.&lt;/p&gt;

&lt;p&gt;So to overcome this problem you have to do something like this in your test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;     const moduleFixture: TestingModule = await Test.createTestingModule({
       imports: [AppModule],
     })
       .overrideProvider(getQueueToken('YOUR_QUEUE_NAME'))
       .useValue({
         on: jest.fn(),
         add: jest.fn(),
         process: jest.fn(),
       })
&lt;span class="gi"&gt;+      .overrideProvider(AudioConsumer)
+      .useValue({})
&lt;/span&gt;       .compile();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And with this you should be good to go.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Issue With Testcontainers
&lt;/h2&gt;

&lt;p&gt;Have not solved it yet. And the real redis instance, I have not figured that out either. BTW you can see the whole conversation of me with me for the most parts &lt;a href="https://discord.com/channels/520622812742811698/1292989048062869597/1292989048062869597" rel="noopener noreferrer"&gt;here in discord&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;If you're passionate about developing safe software for deploying on friday without having to fear this kind of consequences: &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%2Fz43nv88s3y9oh58b8qkp.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%2Fz43nv88s3y9oh58b8qkp.png" alt="Image description" width="512" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You need to start thinking about writing tests and probably E2E or unit tests or a combination of different tests. This gives you the confidence you need to deploy and be sure that with it you have not introduces a bug to the existing feature.&lt;/p&gt;

&lt;p&gt;But for sure the new features always are prone to bugs, but at least you know what you've covered (scenarios) and if something goes wrong you will add that as a new test case to your existing ones. This potentially help you to reduce the amount of fires you need to put out :).&lt;/p&gt;

&lt;p&gt;Make sure to follow me, and also give &lt;a href="https://github.com/kasir-barati/bugs" rel="noopener noreferrer"&gt;my repo&lt;/a&gt; a star: &lt;/p&gt;

&lt;p&gt;Instagram: &lt;a href="https://www.instagram.com/node.js.developers.kh/" rel="noopener noreferrer"&gt;https://www.instagram.com/node.js.developers.kh/&lt;/a&gt;&lt;br&gt;
Facebook: &lt;a href="https://www.facebook.com/kasirbarati" rel="noopener noreferrer"&gt;https://www.facebook.com/kasirbarati&lt;/a&gt;&lt;br&gt;
X: &lt;a href="https://x.com/kasir_barati" rel="noopener noreferrer"&gt;https://x.com/kasir_barati&lt;/a&gt;&lt;br&gt;
YouTube: &lt;a href="https://www.youtube.com/@kasir-barati" rel="noopener noreferrer"&gt;https://www.youtube.com/@kasir-barati&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/kasir-barati/" rel="noopener noreferrer"&gt;https://github.com/kasir-barati/&lt;/a&gt;&lt;br&gt;
Dev.to: &lt;a href="https://dev.to/kasir-barati"&gt;https://dev.to/kasir-barati&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://linkedin.com/in/kasir-barati" rel="noopener noreferrer"&gt;https://linkedin.com/in/kasir-barati&lt;/a&gt;&lt;/p&gt;




</description>
      <category>nestjs</category>
      <category>javascript</category>
      <category>node</category>
      <category>testing</category>
    </item>
    <item>
      <title>Graphile -- Farewell Business Layer</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Mon, 20 Jan 2025 19:18:36 +0000</pubDate>
      <link>https://dev.to/kasir-barati/graphile-farewell-business-layer-4960</link>
      <guid>https://dev.to/kasir-barati/graphile-farewell-business-layer-4960</guid>
      <description>&lt;p&gt;So I am super duper excited about &lt;a href="https://www.graphile.org/" rel="noopener noreferrer"&gt;Graphile&lt;/a&gt;, I just finished listening to an insightful podcast from &lt;a href="https://graphqlradio.com/" rel="noopener noreferrer"&gt;GraphQL Radio&lt;/a&gt; and I enjoyed it quite a lot. But yeah let's forget about my enjoy and focus on this post.&lt;/p&gt;

&lt;p&gt;So in this episode called &lt;a href="https://graphqlradio.com/episodes/postgraphile-and-beyond-w-benjie-gillam-graphql-technical-steering-committee-member" rel="noopener noreferrer"&gt;Benjie Gillam on PostGraphile, The GraphQL Foundation, Independence From Facebook, Supporting Open Source, and beyond&lt;/a&gt; I get to learn more about Graphile and its origin.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Graphile Came to Be
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Originally it was called PostGraphQL.&lt;/li&gt;
&lt;li&gt;Then &lt;a href="https://benjie.dev/" rel="noopener noreferrer"&gt;Benji&lt;/a&gt; collaborate a couple of times on this open-source project and then one day he gets an email that CC him about the new fact, he is now the maintainer of PostGraphQL 😂.&lt;/li&gt;
&lt;li&gt;So he works on it and in the process he renamed it to Graphile since GraphQL is a trademark.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  So What the Heck does Graphile?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Simply put you do not need to write a model to connect to DB, then one for your service layer and eventually also one for your GraphQL. Essentially most of the times we do not need this much work. Especially if you wanna spin a stratup and just wanna ship something.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;So Graphile sits in between and says something like this: hey, you know what? PostgreSQL is so awesome and powerful that it knows better than you how to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Plan a query in the most efficient way. This has a couple of implications:

&lt;ul&gt;
&lt;li&gt;No over fetching or under fetching.&lt;/li&gt;
&lt;li&gt;Extremely optimized queries.&lt;/li&gt;
&lt;li&gt;No need to tackle &lt;a href="https://github.com/kasir-barati/graphql-js-ts/blob/62ac696c1e9080e74170247ec4dee7473af1e95c/docs/nestjs.md#shouldWeUseResolveField" rel="noopener noreferrer"&gt;N+1 issue&lt;/a&gt; anymore.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Handle permissions since like forever (I could not find any concrete evidence as when it was added but &lt;a href="https://github.com/postgres/postgres/commit/6cd67c931a5cdd1a058031c0d02fc3199fafe2a9" rel="noopener noreferrer"&gt;according to this commit in this repo&lt;/a&gt; it was before 2018) with &lt;a href="https://www.postgresql.org/docs/current/sql-grant.html" rel="noopener noreferrer"&gt;&lt;code&gt;GRANT&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://www.postgresql.org/docs/current/sql-revoke.html" rel="noopener noreferrer"&gt;&lt;code&gt;REVOKE&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;

&lt;/ol&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  My Take On This
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Full transparency, I have not used it yet. But I am gonna try it out definitely.&lt;/li&gt;
&lt;li&gt;As I wrote, this is &lt;strong&gt;my&lt;/strong&gt; personal comment on this tool.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For a startup what matters most? &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shipping features fast ✔️.&lt;/li&gt;
&lt;li&gt;Get a quick feedback ✔️.&lt;/li&gt;
&lt;li&gt;Be reliable ✔️.&lt;/li&gt;
&lt;li&gt;Have a good community ✔️.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;So I would love to know if you're using it in your work place, personal project or are assessing for your next big hairy audacious project.&lt;/p&gt;

&lt;h2&gt;
  
  
  On Another Related Note
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Sometimes we do have tons of business logic that we need to implement.&lt;/li&gt;
&lt;li&gt;They cannot be expressed in PostgreSQL.&lt;/li&gt;
&lt;li&gt;Our app's database ain't PostgreSQL.&lt;/li&gt;
&lt;li&gt;Or any other reason.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would suggest if one of those applies to you and you still have lots of CRUD like APIs. And you're asking yourself should I duplicate code or reinvent the wheel I would say you do not need to (unless you wanted to 😁).&lt;/p&gt;

&lt;p&gt;Take a look at this project that I am actively trying to maintain it and make it something really comparable to &lt;a href="https://chillicream.com/docs/hotchocolate/v13" rel="noopener noreferrer"&gt;HotChocolate&lt;/a&gt; in .NET world.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/TriPSs" rel="noopener noreferrer"&gt;
        TriPSs
      &lt;/a&gt; / &lt;a href="https://github.com/TriPSs/nestjs-query" rel="noopener noreferrer"&gt;
        nestjs-query
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Easy CRUD for GraphQL.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;
  &lt;a href="https://tripss.github.io/nestjs-query" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/619836b6018fac0bed739ef5a6bb8b49d235647dbc7840b9bce8163f7659334f/68747470733a2f2f7472697073732e6769746875622e696f2f6e6573746a732d71756572792f696d672f6c6f676f2e737667" width="120" alt="Nestjs-query Logo"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/TriPSs/nestjs-query/actions/workflows/test.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/TriPSs/nestjs-query/actions/workflows/test.yml/badge.svg?branch=master" alt="Test"&gt;&lt;/a&gt;
&lt;a href="https://codecov.io/gh/TriPSs/nestjs-query" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c758d3187cd056d0ea3f1d929c6ab73cbdf928b25134c79b6af8965a95624be8/68747470733a2f2f636f6465636f762e696f2f67682f5472695053732f6e6573746a732d71756572792f6272616e63682f6d61737465722f67726170682f62616467652e7376673f746f6b656e3d32394558373149443250" alt="codecov"&gt;&lt;/a&gt;
&lt;a href="https://snyk.io/test/github/tripss/nestjs-query?targetFile=package.json" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e016fbf7b073e4cf29dd139529d2ad4ba7f79a9dd4b7490cbb7e5d6099b5a61c/68747470733a2f2f736e796b2e696f2f746573742f6769746875622f7472697073732f6e6573746a732d71756572792f62616467652e7376673f74617267657446696c653d7061636b6167652e6a736f6e" alt="Known Vulnerabilities"&gt;&lt;/a&gt;
&lt;a href="https://join.slack.com/t/nestjsquery/shared_invite/zt-27dvu0tye-tOcAmeQ0PRSCEInW6P3h9g" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e1819c7405b6a78fced3c01a8446f0b92e50fc331f36a6debec5471e8d8f05cc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f736c61636b2d6e6573746a7371756572792d627269676874677265656e2e7376673f6c6f676f3d736c61636b" alt="slack"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;nestjs-query&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Nestjs-Query is collection of packages to make crud for &lt;code&gt;graphql&lt;/code&gt; easier.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;While working on projects in nestjs it was very easy to get up and running with graphql however, there were many patterns that were common between the resolvers. In particular querying, sorting and paging.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://tripss.github.io/nestjs-query/docs/introduction/install" rel="nofollow noopener noreferrer"&gt;Install Guide&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Docs&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tripss.github.io/nestjs-query/docs/introduction/getting-started" rel="nofollow noopener noreferrer"&gt;Getting Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tripss.github.io/nestjs-query/docs/introduction/install" rel="nofollow noopener noreferrer"&gt;Install Guide&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tripss.github.io/nestjs-query/docs/introduction/concepts" rel="nofollow noopener noreferrer"&gt;Concepts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tripss.github.io/nestjs-query/docs/introduction/example" rel="nofollow noopener noreferrer"&gt;Example&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tripss.github.io/nestjs-query/docs/persistence/typeorm/getting-started" rel="nofollow noopener noreferrer"&gt;Typeorm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tripss.github.io/nestjs-query/docs/persistence/sequelize/getting-started" rel="nofollow noopener noreferrer"&gt;Sequelize&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tripss.github.io/nestjs-query/docs/graphql/resolvers" rel="nofollow noopener noreferrer"&gt;GraphQL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Packages&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Nestjs-query is composed of multiple packages&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/tripss/nestjs-query/tree/master/packages/core" rel="noopener noreferrer"&gt;&lt;code&gt;@ptc-org/nestjs-query-core&lt;/code&gt;&lt;/a&gt; - Defines all interfaces and utility types implemented by the other packages.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tripss/nestjs-query/tree/master/packages/query-graphql" rel="noopener noreferrer"&gt;&lt;code&gt;@ptc-org/nestjs-query-graphql&lt;/code&gt;&lt;/a&gt; - Package that provides the graphql resolver and decorators for crud endpoints.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tripss/nestjs-query/tree/master/packages/query-typeorm" rel="noopener noreferrer"&gt;&lt;code&gt;@ptc-org/nestjs-query-mongoose&lt;/code&gt;&lt;/a&gt; - Package that implements a Mongoose service that can be used by itself or with the graphql resolver provided by &lt;code&gt;@ptc-org/nestjs-query-graphql&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tripss/nestjs-query/tree/master/packages/query-sequelize" rel="noopener noreferrer"&gt;&lt;code&gt;@ptc-org/nestjs-query-sequelize&lt;/code&gt;&lt;/a&gt; - Package that implements a Sequelize service that can be used by itself or with the graphql resolver provided by &lt;code&gt;@ptc-org/nestjs-query-graphql&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tripss/nestjs-query/tree/master/packages/query-typegoose" rel="noopener noreferrer"&gt;&lt;code&gt;@ptc-org/nestjs-query-typegoose&lt;/code&gt;&lt;/a&gt; - Package that implements a Typegoose service that…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/TriPSs/nestjs-query" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;p&gt;Instagram: &lt;a href="https://www.instagram.com/node.js.developers.kh/" rel="noopener noreferrer"&gt;https://www.instagram.com/node.js.developers.kh/&lt;/a&gt;&lt;br&gt;
Facebook: &lt;a href="https://www.facebook.com/kasirbarati" rel="noopener noreferrer"&gt;https://www.facebook.com/kasirbarati&lt;/a&gt;&lt;br&gt;
X: &lt;a href="https://x.com/kasir_barati" rel="noopener noreferrer"&gt;https://x.com/kasir_barati&lt;/a&gt;&lt;br&gt;
YouTube: &lt;a href="https://www.youtube.com/@kasir-barati" rel="noopener noreferrer"&gt;https://www.youtube.com/@kasir-barati&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/kasir-barati/" rel="noopener noreferrer"&gt;https://github.com/kasir-barati/&lt;/a&gt;&lt;br&gt;
Dev.to: &lt;a href="https://dev.to/kasir-barati"&gt;https://dev.to/kasir-barati&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://linkedin.com/in/kasir-barati" rel="noopener noreferrer"&gt;https://linkedin.com/in/kasir-barati&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;To support us you can &lt;a href="https://github.com/benjie?tab=sponsoring" rel="noopener noreferrer"&gt;support Benji on GitHub&lt;/a&gt; and to support me consider giving &lt;a href="https://github.com/TriPSs/nestjs-query" rel="noopener noreferrer"&gt;this repo&lt;/a&gt; a star.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>node</category>
      <category>graphql</category>
      <category>architecture</category>
    </item>
    <item>
      <title>How to Read or Understand an Open-Source Projects</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Sat, 28 Dec 2024 17:23:37 +0000</pubDate>
      <link>https://dev.to/kasir-barati/how-to-read-or-understand-an-open-source-projects-136j</link>
      <guid>https://dev.to/kasir-barati/how-to-read-or-understand-an-open-source-projects-136j</guid>
      <description>&lt;p&gt;It's always supper fun to dig into coding and try to make sense of open-source libs. it's been a while since I've started to use &lt;code&gt;nestjs-query&lt;/code&gt; in my GraphQL services. It makes a lot of things easier. But I was puzzled with how the underlying implementation for Connection pagination and offset pagination works.&lt;/p&gt;

&lt;p&gt;So I dug the lib and here is my final understanding: &lt;a href="https://github.com/TriPSs/nestjs-query/issues/344#issuecomment-2562805549" rel="noopener noreferrer"&gt;https://github.com/TriPSs/nestjs-query/issues/344#issuecomment-2562805549&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;I do not think it is gonna find its way into the docs someday, but nonetheless I decided to let you know how I get started to work with a new concept (GraphQL) and read this libs codebase in a manner that helped me to understand what's going on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I started with getting familiar with the structure of the root directory in &lt;code&gt;nestjs-query&lt;/code&gt;. Just seeing what we are using and what we have.&lt;/li&gt;
&lt;li&gt;I felt I kinda missed some crucial parts of docs. So I went to the official docs and read a bit more about the packages that resides in this monorepo.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I came back and ran one of the e2e tests in the debug mode. In fact I added plenty of breakpoints in my VSCode and tried to see how it works in general.&lt;/p&gt;

&lt;p&gt;I was really interested in knowing how it generates the resolvers, service layer and integrates with TypeORM.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now I had a pretty good idea about how it works but I still was not able to pin point where exactly in the codebase we are defining the default pagination strategy. That's where I went back to the docs and read it this time top to bottom once more.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;That's when I started to comprehend more and see how it work. Surprisingly it was really a no-brainer, I do not mean it is simple, I mean why they choose to implement certain things the way it's done in the lib. E.g. this lib is using mixins extensively and I love how modular it has made this lib as a result.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Eureka moment. I finally grasped it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this process I can tell you that I several times went back and forth, ran the e2e tests in the debug mode again and again to understand it. So if you tried to apply this approach and did not get the result you wanted do not be discouraged and try yet again.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;BTW if you wanna develop a new GraphQL service in NestJS it is a really great tool to do the mundane and dull tasks with &lt;code&gt;nestjs-query&lt;/code&gt;. So that you can focus on building what matters for your business.&lt;/p&gt;

&lt;p&gt;And besides the fact that I am using it, I am actively as you can see invested in this lib and in fact my aim is to make it something comparable to HotChocolate as I explained it here: &lt;a href="https://github.com/TriPSs/nestjs-query/discussions/333" rel="noopener noreferrer"&gt;https://github.com/TriPSs/nestjs-query/discussions/333&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if you liked this post consider giving this repo a star on GH :).&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/TriPSs" rel="noopener noreferrer"&gt;
        TriPSs
      &lt;/a&gt; / &lt;a href="https://github.com/TriPSs/nestjs-query" rel="noopener noreferrer"&gt;
        nestjs-query
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Easy CRUD for GraphQL.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;
  &lt;a href="https://tripss.github.io/nestjs-query" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/619836b6018fac0bed739ef5a6bb8b49d235647dbc7840b9bce8163f7659334f/68747470733a2f2f7472697073732e6769746875622e696f2f6e6573746a732d71756572792f696d672f6c6f676f2e737667" width="120" alt="Nestjs-query Logo"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/TriPSs/nestjs-query/actions/workflows/test.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/TriPSs/nestjs-query/actions/workflows/test.yml/badge.svg?branch=master" alt="Test"&gt;&lt;/a&gt;
&lt;a href="https://codecov.io/gh/TriPSs/nestjs-query" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c758d3187cd056d0ea3f1d929c6ab73cbdf928b25134c79b6af8965a95624be8/68747470733a2f2f636f6465636f762e696f2f67682f5472695053732f6e6573746a732d71756572792f6272616e63682f6d61737465722f67726170682f62616467652e7376673f746f6b656e3d32394558373149443250" alt="codecov"&gt;&lt;/a&gt;
&lt;a href="https://snyk.io/test/github/tripss/nestjs-query?targetFile=package.json" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e016fbf7b073e4cf29dd139529d2ad4ba7f79a9dd4b7490cbb7e5d6099b5a61c/68747470733a2f2f736e796b2e696f2f746573742f6769746875622f7472697073732f6e6573746a732d71756572792f62616467652e7376673f74617267657446696c653d7061636b6167652e6a736f6e" alt="Known Vulnerabilities"&gt;&lt;/a&gt;
&lt;a href="https://join.slack.com/t/nestjsquery/shared_invite/zt-27dvu0tye-tOcAmeQ0PRSCEInW6P3h9g" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e1819c7405b6a78fced3c01a8446f0b92e50fc331f36a6debec5471e8d8f05cc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f736c61636b2d6e6573746a7371756572792d627269676874677265656e2e7376673f6c6f676f3d736c61636b" alt="slack"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;nestjs-query&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Nestjs-Query is collection of packages to make crud for &lt;code&gt;graphql&lt;/code&gt; easier.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;While working on projects in nestjs it was very easy to get up and running with graphql however, there were many patterns that were common between the resolvers. In particular querying, sorting and paging.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://tripss.github.io/nestjs-query/docs/introduction/install" rel="nofollow noopener noreferrer"&gt;Install Guide&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Docs&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tripss.github.io/nestjs-query/docs/introduction/getting-started" rel="nofollow noopener noreferrer"&gt;Getting Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tripss.github.io/nestjs-query/docs/introduction/install" rel="nofollow noopener noreferrer"&gt;Install Guide&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tripss.github.io/nestjs-query/docs/introduction/concepts" rel="nofollow noopener noreferrer"&gt;Concepts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tripss.github.io/nestjs-query/docs/introduction/example" rel="nofollow noopener noreferrer"&gt;Example&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tripss.github.io/nestjs-query/docs/persistence/typeorm/getting-started" rel="nofollow noopener noreferrer"&gt;Typeorm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tripss.github.io/nestjs-query/docs/persistence/sequelize/getting-started" rel="nofollow noopener noreferrer"&gt;Sequelize&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tripss.github.io/nestjs-query/docs/graphql/resolvers" rel="nofollow noopener noreferrer"&gt;GraphQL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Packages&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Nestjs-query is composed of multiple packages&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/tripss/nestjs-query/tree/master/packages/core" rel="noopener noreferrer"&gt;&lt;code&gt;@ptc-org/nestjs-query-core&lt;/code&gt;&lt;/a&gt; - Defines all interfaces and utility types implemented by the other packages.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tripss/nestjs-query/tree/master/packages/query-graphql" rel="noopener noreferrer"&gt;&lt;code&gt;@ptc-org/nestjs-query-graphql&lt;/code&gt;&lt;/a&gt; - Package that provides the graphql resolver and decorators for crud endpoints.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tripss/nestjs-query/tree/master/packages/query-typeorm" rel="noopener noreferrer"&gt;&lt;code&gt;@ptc-org/nestjs-query-mongoose&lt;/code&gt;&lt;/a&gt; - Package that implements a Mongoose service that can be used by itself or with the graphql resolver provided by &lt;code&gt;@ptc-org/nestjs-query-graphql&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tripss/nestjs-query/tree/master/packages/query-sequelize" rel="noopener noreferrer"&gt;&lt;code&gt;@ptc-org/nestjs-query-sequelize&lt;/code&gt;&lt;/a&gt; - Package that implements a Sequelize service that can be used by itself or with the graphql resolver provided by &lt;code&gt;@ptc-org/nestjs-query-graphql&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tripss/nestjs-query/tree/master/packages/query-typegoose" rel="noopener noreferrer"&gt;&lt;code&gt;@ptc-org/nestjs-query-typegoose&lt;/code&gt;&lt;/a&gt; - Package that implements a Typegoose service that…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/TriPSs/nestjs-query" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;p&gt;Follow me:&lt;br&gt;
Instagram: &lt;a href="https://www.instagram.com/node.js.developers.kh/" rel="noopener noreferrer"&gt;https://www.instagram.com/node.js.developers.kh/&lt;/a&gt;&lt;br&gt;
Facebook: &lt;a href="https://www.facebook.com/kasirbarati" rel="noopener noreferrer"&gt;https://www.facebook.com/kasirbarati&lt;/a&gt;&lt;br&gt;
X: &lt;a href="https://x.com/kasir_barati" rel="noopener noreferrer"&gt;https://x.com/kasir_barati&lt;/a&gt;&lt;br&gt;
YouTube: &lt;a href="https://www.youtube.com/@kasir-barati" rel="noopener noreferrer"&gt;https://www.youtube.com/@kasir-barati&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/kasir-barati/" rel="noopener noreferrer"&gt;https://github.com/kasir-barati/&lt;/a&gt;&lt;br&gt;
Dev.to: &lt;a href="https://dev.to/kasir-barati"&gt;https://dev.to/kasir-barati&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://linkedin.com/in/kasir-barati" rel="noopener noreferrer"&gt;https://linkedin.com/in/kasir-barati&lt;/a&gt; &lt;/p&gt;

</description>
      <category>opensource</category>
      <category>softskill</category>
      <category>tutorial</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Zero, One, Infinity Principle in Software Development</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Wed, 25 Dec 2024 10:44:11 +0000</pubDate>
      <link>https://dev.to/kasir-barati/zero-one-infinity-principle-in-software-development-39p0</link>
      <guid>https://dev.to/kasir-barati/zero-one-infinity-principle-in-software-development-39p0</guid>
      <description>&lt;p&gt;While reading &lt;a href="https://www.apollographql.com/docs/graphos/schema-design/guides/relay-style-connections#do-i-even-need-a-wrapper-type-for-my-lists" rel="noopener noreferrer"&gt;Apollo's doc for Relay Connection pagination&lt;/a&gt; I encountered a new terminology, or let's call it as &lt;a href="https://en.wikipedia.org/wiki/Zero_one_infinity_rule" rel="noopener noreferrer"&gt;Wikipedia does, a new rule of thumb&lt;/a&gt;. But here I prefer to consider it a principle. So from now on I'll call it principle.&lt;/p&gt;

&lt;h2&gt;
  
  
  ZOI -- Zero, One, Infinity Principle
&lt;/h2&gt;

&lt;p&gt;I continued my quest on uncovering this new term and read some interesting posts on Medium, such as "&lt;a href="https://medium.com/@taljoffe/the-zero-one-infinity-rule-760ff7f2c0ff" rel="noopener noreferrer"&gt;The “Zero, One, Infinity” rule&lt;/a&gt;" written by Tal Joffe. But frankly speaking I still felt it is better to share my understanding here and see what you think about is topic.&lt;/p&gt;

&lt;p&gt;So in software engineering this principle acts as some sort of compass. IMO it help us to decide when we need to add a new &lt;a href="https://github.com/kasir-barati/graphql-js-ts/blob/d43cfa9ae4ee0c20cf3a5534f3c79f4caefbf303/docs/glossary.md#indirectionDefinition" rel="noopener noreferrer"&gt;layer of indirection&lt;/a&gt;, or just go with the bare minimum.&lt;/p&gt;

&lt;p&gt;In essence it says we should not restrict how many of a thing (method, instance, etc) can exist in our system. We either have:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Zero&lt;/strong&gt;: You prohibit that thing from existing entirely. Like when you say no freaking way that the root directory in Linux to be placed in another directory (or at least that's how I feel about Linux's root directory).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One&lt;/strong&gt;: Only one instance of something can exists: like root user, we only have one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infinity&lt;/strong&gt;: Create as many as you desire. It's all good. Create as many&lt;sup id="fnref1"&gt;1&lt;/sup&gt; files as you wanted in a directory.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's talk more about its real life implications, rather than theory.&lt;/p&gt;




&lt;h3&gt;
  
  
  Repository Pattern and ZOI ;)
&lt;/h3&gt;

&lt;p&gt;I know you're gonna love this, in fact I am just sharing my take on what Tal Joffe said in his post on Medium. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;He starts by saying that assume we have &lt;code&gt;OrderRepository&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrdersRepository&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;getOrders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="nx"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;[]{&lt;/span&gt;
     &lt;span class="c1"&gt;//...&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;But over time we most likely have something like this:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrdersRepository&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;getOrders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="nx"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;[]{&lt;/span&gt;
     &lt;span class="c1"&gt;//...&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nf"&gt;searchOrders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;searchTerm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;[]{&lt;/span&gt;
     &lt;span class="c1"&gt;//...&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nf"&gt;getOrdersNames&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ids&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]{&lt;/span&gt;
     &lt;span class="c1"&gt;//...&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="c1"&gt;// for the full example read his post. Linked at the beginning of this post.&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;So now imagine you wanna add a new feature and need to have a new query which returns a list of orders. Now first we might look up in our current implementation to see if we have one that matches our requirements. If not we will add yet another one!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Solution to Our Repository Pattern Dilemma
&lt;/h4&gt;

&lt;p&gt;Recall, in ZOI we have 3 state, zero, one, or infinity. Here we have passed the zero point and if we wanna maintain only one &lt;code&gt;getOrders&lt;/code&gt; we need to somehow extract the responsibility of building the query away from this method.&lt;/p&gt;

&lt;p&gt;In other words it should be only responsible for fetching data from the underlying database (SRP -- Single Responsibility Principle from &lt;a href="https://en.wikipedia.org/wiki/SOLID" rel="noopener noreferrer"&gt;SOLID&lt;/a&gt;). To do this we need to add a new layer on indirection. We need to do this since we need to follow &lt;a href="https://github.com/kasir-barati/clean-code-in-js-ts/tree/open-close-principle-payment-gateway" rel="noopener noreferrer"&gt;Open/Close Principle&lt;/a&gt; too. We will create a new query builder using the builder pattern&lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FindManyOptions&lt;/span&gt;&lt;span class="p"&gt;,&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;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typeorm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Cursor&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="p"&gt;}&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ForwardPaginationArgs&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Cursor&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;after&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Cursor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;first&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;BackwardPaginationArgs&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Cursor&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;after&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Cursor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;first&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;QueryBuilder&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Entity&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;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FindManyOptions&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Entity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;setWhere&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="na"&gt;forwardPaging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ForwardPaginationArgs&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Cursor&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;backwardPaging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BackwardPaginationArgs&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Cursor&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="nx"&gt;QueryBuilder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;setCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="na"&gt;forwardPaging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ForwardPaginationArgs&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Cursor&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;backwardPaging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BackwardPaginationArgs&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Cursor&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="nx"&gt;QueryBuilder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;FindManyOptions&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Entity&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="kr"&gt;interface&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;Entity&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;getMany&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;queryBuilder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;QueryBuilder&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Entity&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;Entity&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;h5&gt;
  
  
  GitHub Repo for Repository Pattern
&lt;/h5&gt;

&lt;p&gt;In here you can see how I am using this pattern in Practice: &lt;a href="https://github.com/kasir-barati/graphql-js-ts/blob/ded01b731159b969ff7f2e7f902e499eb8c427ee/libs/shared/src/services/pager/query-service.pager.ts#L11-L16" rel="noopener noreferrer"&gt;kasir-barati/graphql-js-ts/libs/shared/src/services/pager/query-service.pager.ts&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Lemme know what you think and I encourage you to gimme a star to my  GitHub repo so that more people can reach to this useful tip 🦾.&lt;/p&gt;




&lt;h3&gt;
  
  
  Relay Connection Pagination
&lt;/h3&gt;

&lt;p&gt;Whenever we have a list in our API we most likely sooner or later run into the problem of needing pagination. So with that in mind the next question will become how it relates to ZOI.&lt;/p&gt;

&lt;p&gt;ZOI says if you do not wanna allow it do not allow it and that's fine (Zero scenario). Or maybe you just wanna have one &lt;code&gt;getOrders&lt;/code&gt; and that's fine too (One scenario). Or like here we'll have an infinite number of records, so what ZOI suggest is to handle this scenario gracefully.&lt;/p&gt;

&lt;p&gt;Meaning if you do not follow ZOI's suggestion the likelihood of building our GraphQL schema like this is high:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Comment&lt;/span&gt;&lt;span class="p"&gt;!]!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whereas we might have developed it like the following when we have the ZOI principle in mind:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;commentsConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CommentConnection&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CommentConnection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CommentEdge&lt;/span&gt;&lt;span class="p"&gt;!]!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;pageInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PageInfo&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Comment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CommentEdge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Comment&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PageInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;hasNextPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;hasPreviousPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;startCursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;endCursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Learn more about pagination &lt;a href="https://github.com/kasir-barati/graphql-js-ts/blob/main/docs/best-practices/pagination.md" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;If this was useful to you consider giving me a star on GH on one of my repos that you've found it helpful.&lt;/p&gt;

&lt;p&gt;BTW Follow me:&lt;br&gt;
Instagram: &lt;a href="https://www.instagram.com/node.js.developers.kh/" rel="noopener noreferrer"&gt;https://www.instagram.com/node.js.developers.kh/&lt;/a&gt;&lt;br&gt;
Facebook: &lt;a href="https://www.facebook.com/kasirbarati" rel="noopener noreferrer"&gt;https://www.facebook.com/kasirbarati&lt;/a&gt;&lt;br&gt;
X: &lt;a href="https://x.com/kasir_barati" rel="noopener noreferrer"&gt;https://x.com/kasir_barati&lt;/a&gt;&lt;br&gt;
YouTube: &lt;a href="https://www.youtube.com/@kasir-barati" rel="noopener noreferrer"&gt;https://www.youtube.com/@kasir-barati&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/kasir-barati/" rel="noopener noreferrer"&gt;https://github.com/kasir-barati/&lt;/a&gt;&lt;br&gt;
Dev.to: &lt;a href="https://dev.to/kasir-barati"&gt;https://dev.to/kasir-barati&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://linkedin.com/in/kasir-barati" rel="noopener noreferrer"&gt;https://linkedin.com/in/kasir-barati&lt;/a&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;I know practically we cannot create "as many" as we wanted files in a directory since there are some other factors that restrict us from doing that (learn more &lt;a href="https://stackoverflow.com/a/466596/8784518" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;strong&gt;BUT&lt;/strong&gt; the point that ZOI is trying to make it clear is, that we ain't gonna restrict users by some arbitrary numbers. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;You can learn more about Builder Pattern &lt;a href="https://refactoring.guru/design-patterns/builder" rel="noopener noreferrer"&gt;here&lt;/a&gt; and see how I use it in practice &lt;a href="https://github.com/kasir-barati/graphql-js-ts/blob/d43cfa9ae4ee0c20cf3a5534f3c79f4caefbf303/apps/todo-nest-e2e/src/support/builders/todo.builder.ts" rel="noopener noreferrer"&gt;here&lt;/a&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>softwaredevelopment</category>
      <category>principle</category>
      <category>software</category>
      <category>designprinciple</category>
    </item>
    <item>
      <title>GraphQL query complexity + NestJS + Dataloader</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Tue, 24 Dec 2024 14:59:08 +0000</pubDate>
      <link>https://dev.to/kasir-barati/graphql-query-complexity-nestjs-dataloader-2p2m</link>
      <guid>https://dev.to/kasir-barati/graphql-query-complexity-nestjs-dataloader-2p2m</guid>
      <description>&lt;p&gt;I was doing some exploration around GraphQL query complexity, depth limitation, and how to incorporate dataloader in NestJS to make my GraphQL API faster.&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%2Fzaih8mjbhn4n1ui3j6j3.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%2Fzaih8mjbhn4n1ui3j6j3.png" alt="Heads up" width="400" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Just before getting into details I need to clarify that &lt;strong&gt;this is a contrived example&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UPDATE&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;I just saw &lt;a href="https://github.com/sonofmagic/graphql-depth-limit-ts/issues/14" rel="noopener noreferrer"&gt;this issue in &lt;code&gt;graphql-depth-limit-ts&lt;/code&gt;&lt;/a&gt; about &lt;a href="https://relay.dev/graphql/connections.htm" rel="noopener noreferrer"&gt;Connection Spec&lt;/a&gt; for pagination. Frankly speaking I did not consider this at all 😅. So right now I think my implementation can be enhanced to cover this case too.&lt;/li&gt;
&lt;li&gt;I've found a better lib that does both static query cost analysis and depth limiting. It is &lt;a href="https://www.npmjs.com/package/@escape.tech/graphql-armor" rel="noopener noreferrer"&gt;&lt;code&gt;@escape.tech/graphql-armor&lt;/code&gt;&lt;/a&gt;. Make sure to &lt;a href="https://github.com/Escape-Technologies/graphql-armor/discussions/754" rel="noopener noreferrer"&gt;take a look at my discussion&lt;/a&gt; too.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Database state
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A dockerized PostgreSQL version 17.&lt;/li&gt;
&lt;li&gt;I have about 1,000 users.&lt;/li&gt;
&lt;li&gt;Each user has about 100 posts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resolver
&lt;/h2&gt;

&lt;p&gt;I am fetching only 5 posts when you execute the following query inside the resolver for the &lt;code&gt;getPosts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;getPosts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But in the &lt;code&gt;posts&lt;/code&gt; resolver I decided to fetch all of their posts (100). And that's where the bottleneck is. &lt;/p&gt;
&lt;h2&gt;
  
  
  Statistics before Dataloader
&lt;/h2&gt;

&lt;p&gt;It was talking &lt;strong&gt;up to 5.5 seconds&lt;/strong&gt; to retrieve data. And it was freaking huge. As you might have guessed it, I was using &lt;code&gt;@ResolveField&lt;/code&gt; and sending a separate &lt;code&gt;SELECT&lt;/code&gt; command to my underlying database.&lt;/p&gt;
&lt;h2&gt;
  
  
  Statistics after Dataloader
&lt;/h2&gt;

&lt;p&gt;Now it fetches the same dataset in &lt;strong&gt;~3.7 seconds&lt;/strong&gt;. It is 32% performance increase. This might sound a bit disappointing but look at it this way:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;This is a contrived example.&lt;/li&gt;
&lt;li&gt;Take into account all those I/O costs that will be eliminated to some extend.&lt;/li&gt;
&lt;li&gt;You do not need to pay more than you have to (in pay-as-you-go payment model your database instance was constantly being hit with new requests).&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Repo
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kasir-barati" rel="noopener noreferrer"&gt;
        kasir-barati
      &lt;/a&gt; / &lt;a href="https://github.com/kasir-barati/graphql-js-ts" rel="noopener noreferrer"&gt;
        graphql-js-ts
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Where you can learn all about GraphQL and its intricacies
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-alert markdown-alert-caution"&gt;
&lt;p class="markdown-alert-title"&gt;Caution&lt;/p&gt;
&lt;p&gt;Keep this file in sync with &lt;a href="https://github.com/kasir-barati/graphql-js-ts../index.md" rel="noopener noreferrer"&gt;&lt;code&gt;index.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;GraphQL&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-alert markdown-alert-tip"&gt;
&lt;p class="markdown-alert-title"&gt;Tip&lt;/p&gt;
&lt;p&gt;Just for those curious minds who always jump from one branch to another like mine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/hasura.md" rel="noopener noreferrer"&gt;Hasura&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.apollographql.com/blog/graphql-vs-rest" rel="nofollow noopener noreferrer"&gt;GraphQL VS REST&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/testing-graphql.md" rel="noopener noreferrer"&gt;Testing GraphQL API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;p&gt;You can find a good definition usually in &lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/glossary.md" rel="noopener noreferrer"&gt;glossary&lt;/a&gt;.&lt;/p&gt;


&lt;ol&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/intro.md" rel="noopener noreferrer"&gt;Intro&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/data-types.md" rel="noopener noreferrer"&gt;Data types&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;A simple todo app written with GraphQL + ReactJS + Relay

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/graphql-js-ts../apps/todo-backend/README.md" rel="noopener noreferrer"&gt;Backend&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/graphql-js-ts" rel="noopener noreferrer"&gt;Frontend&lt;/a&gt; TK.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/queries-and-mutations.md" rel="noopener noreferrer"&gt;Queries and mutations in depth&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/graphql-query-language-breakdown.md" rel="noopener noreferrer"&gt;Let's breakdown the query language a bit more&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/function-provided-by-graphql.md" rel="noopener noreferrer"&gt;Functions provided by &lt;code&gt;graphql&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/documentation.md" rel="noopener noreferrer"&gt;Document your GraphQL service API&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/graphql-req-lifecycle.md" rel="noopener noreferrer"&gt;GraphQL request lifecycle&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/common-errors.md" rel="noopener noreferrer"&gt;Common validation errors&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/execution-from-inside.md" rel="noopener noreferrer"&gt;Execution from inside, resolver's args, AST, ...&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/code-first.md" rel="noopener noreferrer"&gt;Code-first approach&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/auth.md" rel="noopener noreferrer"&gt;Auth&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/introspection.md" rel="noopener noreferrer"&gt;How to query information about a GraphQL schema&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/improve-dev-exp/index.md" rel="noopener noreferrer"&gt;Improve developer experience&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/improve-dev-exp/ioc.md" rel="noopener noreferrer"&gt;IoC -- Inversion of Control principle&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/improve-dev-exp/use-schema-graphql-files.md" rel="noopener noreferrer"&gt;Use a &lt;code&gt;schema.graphql&lt;/code&gt; file&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/improve-dev-exp/strongly-typed.md" rel="noopener noreferrer"&gt;Strongly typed resolvers, context, ...&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/improve-dev-exp/filtering-using-prisma-nestjs-graphql.md" rel="noopener noreferrer"&gt;Filtering using &lt;code&gt;prisma-nestjs-graphql&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/security.md" rel="noopener noreferrer"&gt;Security in GraphQL&lt;/a&gt;.&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/kasir-barati/graphql-js-ts../docs/nestjs.md" rel="noopener noreferrer"&gt;NestJS&lt;/a&gt;

&lt;ul&gt;&lt;li&gt;…&lt;/li&gt;&lt;/ul&gt;


&lt;/li&gt;

&lt;/ol&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kasir-barati/graphql-js-ts" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;There go for: &lt;code&gt;apps/dataloader-example&lt;/code&gt;. BTW in this repo you can see my implementation of static query cost analysis which you can learn more about it &lt;a href="https://github.com/kasir-barati/graphql-js-ts/blob/main/docs/best-practices/cost-analysis.md" rel="noopener noreferrer"&gt;here&lt;/a&gt;. The part that I especially proud of is where I incorporated depth of a field in the overall complexity of a field (for context look at this &lt;a href="https://github.com/slicknode/graphql-query-complexity/issues/96" rel="noopener noreferrer"&gt;issue&lt;/a&gt;).&lt;/p&gt;




&lt;p&gt;If this helped you consider giving me a star on my GitHub repo for this Post :).&lt;/p&gt;




&lt;p&gt;Follow me:&lt;/p&gt;

&lt;p&gt;Instagram: &lt;a href="https://www.instagram.com/node.js.developers.kh/" rel="noopener noreferrer"&gt;https://www.instagram.com/node.js.developers.kh/&lt;/a&gt;&lt;br&gt;
Facebook: &lt;a href="https://www.facebook.com/kasirbarati" rel="noopener noreferrer"&gt;https://www.facebook.com/kasirbarati&lt;/a&gt;&lt;br&gt;
X: &lt;a href="https://x.com/kasir_barati" rel="noopener noreferrer"&gt;https://x.com/kasir_barati&lt;/a&gt;&lt;br&gt;
YouTube: &lt;a href="https://www.youtube.com/@kasir-barati" rel="noopener noreferrer"&gt;https://www.youtube.com/@kasir-barati&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/kasir-barati/" rel="noopener noreferrer"&gt;https://github.com/kasir-barati/&lt;/a&gt;&lt;br&gt;
Dev.to: &lt;a href="https://dev.to/kasir-barati"&gt;https://dev.to/kasir-barati&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://linkedin.com/in/kasir-barati" rel="noopener noreferrer"&gt;https://linkedin.com/in/kasir-barati&lt;/a&gt; &lt;/p&gt;

</description>
      <category>nestjs</category>
      <category>graphql</category>
      <category>dataloader</category>
      <category>node</category>
    </item>
    <item>
      <title>GraphQL + NestJS -- Part 1</title>
      <dc:creator>Mohammad Jawad (Kasir) Barati</dc:creator>
      <pubDate>Sun, 15 Dec 2024 11:18:07 +0000</pubDate>
      <link>https://dev.to/kasir-barati/graphql-nestjs-part-1-4938</link>
      <guid>https://dev.to/kasir-barati/graphql-nestjs-part-1-4938</guid>
      <description>&lt;p&gt;So I have this job op with GraphQL requirements, thus I decided to prepare myself for the position.&lt;/p&gt;

&lt;p&gt;First I &lt;a href="https://graphql.org/learn/" rel="noopener noreferrer"&gt;read the GraphQL doc here&lt;/a&gt;, then I started to redocument it since TBH I find it more engaging when I write doc for a tech than simply reading it (the result can be found &lt;a href="https://github.com/kasir-barati/graphql-js-ts" rel="noopener noreferrer"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Then after that I decided to get a bit exercise in NestJS, thus I read their doc as well (RTFM) &lt;a href="https://docs.nestjs.com/graphql/" rel="noopener noreferrer"&gt;here&lt;/a&gt;. So now I reached a point where I realized I do not wanna spend my precious time writing CRUD-like ops.&lt;/p&gt;

&lt;p&gt;So I tried out a couple of packages such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;prisma-nestjs-graphql&lt;/code&gt;: You can find my conclusion about it &lt;a href="https://github.com/kasir-barati/graphql-js-ts/blob/main/docs/improve-dev-exp/filtering-using-prisma-nestjs-graphql.md" rel="noopener noreferrer"&gt;here&lt;/a&gt;. But if you wanna know the final answer, it is a big &lt;strong&gt;NO&lt;/strong&gt; for me.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/TriPSs/nestjs-query" rel="noopener noreferrer"&gt;&lt;code&gt;nestjs-query&lt;/code&gt;&lt;/a&gt;: I tried this one and switched from Prisma to TypeORM. Like always I am documenting what I am doing &lt;a href="https://github.com/kasir-barati/nestjs-materials/tree/main/docs/nestjs-query" rel="noopener noreferrer"&gt;here&lt;/a&gt;. But the bottom line is that this lib won the prize.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So now that I've cleared the air first I can explain from where I started my journey:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Like I said I decided to develop a dummy NestJS app with GraphQL to have a feeling for what's it like to build a GraphQL API. Talking more accurate, I was really interested in knowing "pagination and filtering".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I went TDD, meaning I wrote my e2e tests first. Thus I faced a big picture kind of question: "how my API should look like?"&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How others approach this question?&lt;/li&gt;
&lt;li&gt;Do we have a standard way of doing things?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then A more fundamental question hit me, how should I go about caching? So I asked google about it and in the results I found &lt;a href="https://www.youtube.com/watch?v=MPRQRlrixls" rel="noopener noreferrer"&gt;a very insightful video about caching in GraphQL&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;By this time I was feeling more confused than before. So I just decided to narrow the question down to what is the most common practice to have pagination in GraphQL and soon I found my answer. It is called "Connections" and I thought that those guys at Facebook ought to need caching. So it is pretty safe to use it.&lt;/p&gt;

&lt;p&gt;BTW in case you like to know about pagination intricacies and its variants you can read my doc over &lt;a href="https://github.com/kasir-barati/nestjs-materials/blob/main/docs/designing-restful-api/pagination.md#pagination" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And if you are interested in "Connections" design pattern read &lt;a href="https://github.com/kasir-barati/graphql-js-ts/blob/main/docs/best-practices/pagination.md" rel="noopener noreferrer"&gt;this doc&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now I am writing E2E tests for this dummy NestJS app called &lt;code&gt;botprobe-nest&lt;/code&gt; &lt;a href="https://github.com/kasir-barati/nestjs-materials/tree/main/typeorm/apps/botprobe-nest-e2e" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Have not pushed anything yet though at the time of writing this article.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My next stop would be contributing more in &lt;a href="https://github.com/TriPSs/nestjs-query" rel="noopener noreferrer"&gt;&lt;code&gt;nestjs-query&lt;/code&gt;&lt;/a&gt; project since it lacks some stuff that I think I need for sure.&lt;/p&gt;

&lt;p&gt;BTW I just did &lt;a href="https://github.com/TriPSs/nestjs-query/pull/330" rel="noopener noreferrer"&gt;upgrade a 3rd-party lib to its latest major version&lt;/a&gt;, thus we also release version 8.0.0.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next step
&lt;/h2&gt;

&lt;p&gt;After I finish writing E2E tests I am gonna try out caching, &lt;strong&gt;but&lt;/strong&gt; before that we need to take care of query complexity. So stay tuned for the next part. Also lemme know in the comments if I can improve something.&lt;/p&gt;

</description>
      <category>nestjs</category>
      <category>node</category>
      <category>backend</category>
      <category>graphql</category>
    </item>
  </channel>
</rss>
