<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ nestjs - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ nestjs - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 18 Jun 2026 11:20:20 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/nestjs/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build an AI Agent with LangChain and LangGraph: Build an Autonomous Starbucks Agent ]]>
                </title>
                <description>
                    <![CDATA[ Back in 2023, when I started using ChatGPT, it was just another chatbot that I could ask complex questions to and it would identify errors in my code snippets. Everything was fine. The application had no memory of previous states or what was said the... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-starbucks-ai-agent-with-langchain/</link>
                <guid isPermaLink="false">69449a6dcd2a4eec1f27eb1b</guid>
                
                    <category>
                        <![CDATA[ ai agents ]]>
                    </category>
                
                    <category>
                        <![CDATA[ langchain ]]>
                    </category>
                
                    <category>
                        <![CDATA[ nestjs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Djibril-M🍀 ]]>
                </dc:creator>
                <pubDate>Fri, 19 Dec 2025 00:21:01 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765630477745/8dffec85-c3c4-4d83-9aa4-f332439d4663.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Back in 2023, when I started using ChatGPT, it was just another chatbot that I could ask complex questions to and it would identify errors in my code snippets. Everything was fine. The application had no memory of previous states or what was said the day before.</p>
<p>Then in 2024, everything started to change. We went from a stateless chatbot to an AI agent that could call tools, search the internet, and generate download links.</p>
<p>At this point, I started to get curious. How can an LLM search the internet? An infinite number of questions were flowing through my head. Can it create its own tools, programs, or execute its own code? It felt like we were heading toward the Skynet (Terminator) revolution.</p>
<p>I was just ignorant 😅. But that's when I started my research and discovered LangChain, a tool that promises all those miracles without a billion-dollar budget.</p>
<p>In this article, you’ll build a fully functional AI agent using LangChain and LangGraph. You’ll start by defining structured data using Zod schemas, then parsing them for AI understanding. Next, you’ll learn about summarizing data into text, creating tools the agent can call, and setting up LangGraph nodes to orchestrate workflows.</p>
<p>You’ll see how to compile the workflow graph, manage state, and persist conversation history using MongoDB. By the end, you’ll have a working Starbucks barista AI that demonstrates how to combine reasoning, tool execution, and memory in a single agent.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-an-llm-agent">What is an LLM Agent?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-project-setup">Project Setup</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-data-schematization-with-zod">Data Schematization with Zod</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-parse-the-schema">How to Parse the Schema</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-data-to-text-summarization">Data-to-Text Summarization</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-persist-orders-with-mongodb-in-nestjs">How to Persist Orders with MongoDB in NestJS</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-langgraph-stateannotation-terms">LangGraph State/Annotation Terms</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-tools-for-the-agent">How to Create Tools for the Agent</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-langgraph-nodes-workflow-components">LangGraph Nodes (Workflow Components)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-graph-declaration">Graph Declaration</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-workflow-compilation-and-state-persistence-final-part">Workflow Compilation and State Persistence (Final Part)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To take full advantage of this article, you should have a basic understanding of TypeScript, Node.js, and a bit of NestJS will help, as it’s the backend framework we’ll be using.</p>
<h2 id="heading-what-is-an-llm-agent"><strong>What is an LLM Agent?</strong></h2>
<p>By definition, an LLM agent is a software program that’s capable of perceiving its environment, making decisions, and taking autonomous actions to achieve specific goals. It often does this by interacting with tools and systems.</p>
<p>Many frameworks and conventions were created to achieve this, and one of the most famous and widely used is the ReAct (Reason &amp; Act) framework.</p>
<p>With this framework, the LLM receives a prompt, thinks, decides the next action (this can be calling a specific tool), and receives the tool data. Once the tool’s response has been received, the AI model observes the response, generates its own response, and plans its next actions based on the tool’s response.</p>
<p>You can read more about this concept on the official <a target="_blank" href="https://arxiv.org/abs/2210.03629">white paper</a>. And here’s a diagram that summarizes the entire process:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765064426716/b1e6d7b2-4e4b-43c4-af5c-9cd49b27a864.png" alt="Diagram illustrating an LLM agent workflow: the agent receives a prompt, reasons, decides an action (such as calling a tool), observes the tool’s response, generates its own response, and iteratively plans its next actions using the ReAct framework" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Note that the workflow is not limited to a single tool invocation – it can proceed through several rounds before returning to the user.</p>
<p>But for an LLM agent to be truly human-like and act with knowledge of the past, it requires a memory. This enables it to recall previous prompts and responses, maintaining consistency within the given thread.</p>
<p>There’s no single source of truth for how to approach this. Most agents implement a short-term memory. This means that the agent will append each new chat to the conversation history, and when a new prompt is submitted, the agent will append the previous messages to the new prompt.</p>
<p>This method is very efficient and gives the LLM a strong knowledge of previous states. But it can also introduce problems, because the more the conversation grows, the more the LLM will have to go through all previous messages in order to understand what action to take next.</p>
<p>And this can introduce some context drift, just like humans experience. You can’t watch a two-hour podcast and remember all the spoken words, right? In this scenario, the LLM will focus on the most relevant information, eventually losing some context.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765064542431/18b8d0a7-b9f1-4f7d-993d-76b3c4058ccf.png" alt="Illustration showing an LLM agent workflow with memory: the agent processes multiple rounds of prompts and tool interactions, maintains a short-term memory of previous conversations, and uses this context to decide actions, while older context may fade over time causing potential context drift." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>You don’t have to implement this from scratch. Many tools and frameworks have been developed to make the implementation as easy as possible. You can build it from scratch if you want, of course, but we won’t be doing that here.</p>
<p>In this article, we’ll build a Starbucks barista that collects order information and calls a <code>create_order</code> tool once the order meets the full criteria. This is a tool that we’ll create and expose to the AI.</p>
<h2 id="heading-project-setup">Project Setup</h2>
<p>Let’s start by initializing our project. We’ll use Nest.js for its efficiency and native TypeScript support. Note that nothing here is tied to Nest.js – this is just a framework preference, and everything we’ll do here can be done with Node.js and Express.js.</p>
<p>Here is a list of all the tools that we’ll use:</p>
<ol>
<li><p><code>langchain/core</code> - <strong>Always required</strong></p>
<p> This is the main Langchain engine that defines all core tools and fundamental functions, containing:</p>
<ul>
<li><p>prompt templates</p>
</li>
<li><p>message types</p>
</li>
<li><p>runnables</p>
</li>
<li><p>tool interfaces</p>
</li>
<li><p>chain composition utilities, and more.</p>
</li>
</ul>
</li>
</ol>
<p>    Most LangChain project need this.</p>
<ol start="2">
<li><p><code>langchain/google-genai</code> - This package is used to interact with Google’s generative AI models, vector embedding models, and other related tools.</p>
</li>
<li><p><code>langchain/langgraph</code> - <strong>Important for building an AI agent with total control</strong></p>
<p> Langgraph is a low-level orchestration framework for building controllable agents. It can be used to build:</p>
<ul>
<li><p>Conversational agents.</p>
</li>
<li><p>Build complex task automation.</p>
</li>
<li><p>Agent’s context management.</p>
</li>
</ul>
</li>
<li><p><code>langchain/langgraph-checkpoint-mongodb</code> - This package provides a MongoDB-based checkpointer for LangGraph, enabling persistence of agent state and short-term memory using MongoDB.</p>
</li>
<li><p><code>@langchain/mongodb</code> - This package provides MongoDB integrations for LangChain, allowing you to:</p>
<ul>
<li><p>Store and retrieve vector embeddings.</p>
</li>
<li><p>Persist LangChain documents, agents, or memory states.</p>
</li>
<li><p>Easily integrate MongoDB as a database backend for your AI workflows.</p>
</li>
</ul>
</li>
<li><p><code>@nestjs/mongoose</code> - A NestJS wrapper around Mongoose for MongoDB. Provides:</p>
<ul>
<li><p>Dependency injection support for Mongoose models.</p>
</li>
<li><p>Simplified schema definition and model management.</p>
</li>
<li><p>Seamless integration of MongoDB into NestJS applications, enabling structured data persistence for AI apps or any backend.</p>
</li>
</ul>
</li>
<li><p><code>langchain</code> - This is the main npm package that aggregates LangChain functionality. It provides:</p>
<ul>
<li><p>Access to connectors, utilities, and core modules.</p>
</li>
<li><p>Easy import of different LangChain components in one place.</p>
</li>
<li><p>Commonly used alongside <code>@langchain/core</code> for building applications with minimal setup.</p>
</li>
</ul>
</li>
<li><p><code>mongodb</code> - The official MongoDB driver for Node.js. It provides:</p>
<ul>
<li><p>Low-level, flexible access to MongoDB databases.</p>
</li>
<li><p>Support for CRUD operations, transactions, and indexing.</p>
</li>
<li><p>A required dependency if you plan to connect LangChain components or your backend directly to MongoDB.</p>
</li>
</ul>
</li>
<li><p><code>mongoose</code> - An ODM (Object Data Modeling) library for MongoDB. Offers:</p>
<ul>
<li><p>Schema-based data modeling for MongoDB documents.</p>
</li>
<li><p>Middleware, validation, and hooks for MongoDB operations.</p>
</li>
<li><p>Ideal for structured data management in NestJS or other Node.js applications.</p>
</li>
</ul>
</li>
<li><p><code>zod</code> - A TypeScript-first schema validation library. Used for:</p>
<ul>
<li><p>Defining strict data schemas and validating inputs/outputs.</p>
</li>
<li><p>Ensuring type safety at runtime.</p>
</li>
<li><p>Useful in AI applications to validate responses from models or enforce data consistency.</p>
</li>
</ul>
</li>
</ol>
<p>Start by initializing your Nest.js project, and installing all the required dependencies:</p>
<pre><code class="lang-dart">$ npm i -g <span class="hljs-meta">@nestjs</span>/cli <span class="hljs-comment">//If you don't have Nest.js installed on your machine</span>
$ nest <span class="hljs-keyword">new</span> project-name

<span class="hljs-string">"dependencies"</span> : {
    <span class="hljs-string">"@langchain/core"</span>: <span class="hljs-string">"^0.3.75"</span>,
    <span class="hljs-string">"@langchain/google-genai"</span>: <span class="hljs-string">"^0.2.16"</span>,
    <span class="hljs-string">"@langchain/langgraph"</span>: <span class="hljs-string">"^0.4.8"</span>,
    <span class="hljs-string">"@langchain/langgraph-checkpoint-mongodb"</span>: <span class="hljs-string">"^0.1.1"</span>,
    <span class="hljs-string">"@langchain/mongodb"</span>: <span class="hljs-string">"^0.1.0"</span>,
    <span class="hljs-string">"@nestjs/mongoose"</span>: <span class="hljs-string">"^11.0.3"</span>,
    <span class="hljs-string">"langchain"</span>: <span class="hljs-string">"^0.3.33"</span>,
    <span class="hljs-string">"mongodb"</span>: <span class="hljs-string">"^6.19.0"</span>,
    <span class="hljs-string">"mongoose"</span>: <span class="hljs-string">"^8.18.1"</span>,
    <span class="hljs-string">"zod"</span>: <span class="hljs-string">"^4.1.8"</span>
}

<span class="hljs-comment">//The versions may not be same at the time you are reading this, so I recommand checking</span>
<span class="hljs-comment">//The official documentation for each package.</span>
</code></pre>
<p>Now that we have our project created and all the packages installed, let’s see what we need to do to turn our vision into a project. Think of what you’ll need in order to create a Starbucks barista:</p>
<ul>
<li><p>First, we need to define the structure of our data (creating schemas)</p>
</li>
<li><p>Then we need to create a menu list that our agent will be referring to.</p>
</li>
<li><p>After that, we’ll add LLM interaction</p>
</li>
<li><p>And last but not least, we’ll add the ability to save previous conversations for conversational context.</p>
</li>
</ul>
<h3 id="heading-folder-structure">Folder Structure</h3>
<p>You can modify this folder structure and adapt it based on your framework of choice. But the core implementation is the same across all frameworks.</p>
<pre><code class="lang-plaintext">├── .env
├── .eslintrc.js
├── .gitignore
├── .prettierrc
├── nest-cli.json
├── package.json
├── README.md
├── tsconfig.build.json
├── tsconfig.json
├── src/
│   ├── app.controller.ts
│   ├── app.module.ts
│   ├── app.service.ts
│   ├── main.ts
│   ├── chat/
│   │   ├── chat.controller.ts
│   │   ├── chat.module.ts
│   │   ├── chat.service.ts
│   │   └── dtos/
│   │       └── chat.dto.ts
│   ├── data/
│   │   └── schema/
│   │       └── order.schema.ts
│   └── util/
│       ├── constants/
│       │   └── drinks_data.ts
│       ├── schemas/
│       │   ├── drinks/
│       │   │   └── Drink.schema.ts
│       │   └── orders/
│       │       └── Order.schema.ts
│       ├── summeries/
│       │   └── drink.ts
│       └── types/
</code></pre>
<h2 id="heading-data-schematization-with-zod">Data Schematization with Zod</h2>
<p>This file contains all our schema definitions regarding drinks and all modifications they can receive. This part is useful for defining the structure of the data that will be used by the AI agent.</p>
<h3 id="heading-importing-zod"><strong>Importing Zod</strong></h3>
<p>In the <code>lib/util/schemas/drinks.ts</code> file, before defining any schemas, import the Zod library, which provides tools for building TypeScript-first schemas.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Imports the 'z' object from the 'zod' library.</span>
<span class="hljs-comment">// Zod is a TypeScript-first schema declaration and validation library.</span>
<span class="hljs-comment">// 'z' is the primary object used to define schemas (e.g., z.object, z.string, z.boolean, z.array).</span>
<span class="hljs-keyword">import</span> z <span class="hljs-keyword">from</span> <span class="hljs-string">"zod"</span>;
</code></pre>
<p>Zod gives you a simple and expressive way to define and validate the structure of the data our agent will interact with.</p>
<h3 id="heading-drink-schema"><strong>Drink Schema</strong></h3>
<p>This schema represents the structure of a drink in the Starbucks-style menu. I split and explained each field so the reader clearly understands what each property controls.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> DrinkSchema = z.object({
  name: z.string(),            <span class="hljs-comment">// Required name of the drink</span>
  description: z.string(),     <span class="hljs-comment">// Required explanation of what the drink is</span>
  supportMilk: z.boolean(),    <span class="hljs-comment">// Whether milk options are available</span>
  supportSweeteners: z.boolean(), <span class="hljs-comment">// Whether sweeteners can be added</span>
  supportSyrup: z.boolean(),   <span class="hljs-comment">// Whether flavor syrups are allowed</span>
  supportTopping: z.boolean(), <span class="hljs-comment">// Whether toppings are supported</span>
  supportSize: z.boolean(),    <span class="hljs-comment">// Whether the drink can be ordered in sizes</span>
  image: z.string().url().optional(), <span class="hljs-comment">// Optional image URL</span>
});
</code></pre>
<h3 id="heading-what-this-schema-represents"><strong>What this schema represents</strong></h3>
<ul>
<li><p>It ensures every drink has a proper name and a description.</p>
</li>
<li><p>It defines which customizations apply to the drink.</p>
</li>
<li><p>It prepares the agent to reason about drink options in a structured, validated format.</p>
</li>
</ul>
<h3 id="heading-sweetener-schema"><strong>Sweetener Schema</strong></h3>
<p>Each sweetener option in the menu is represented with its own schema.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> SweetenerSchema = z.object({
  name: z.string(),                <span class="hljs-comment">// Sweetener name</span>
  description: z.string(),         <span class="hljs-comment">// What it is / taste description</span>
  image: z.string().url().optional(), <span class="hljs-comment">// Optional image URL</span>
});
</code></pre>
<p>This ensures consistency across all sweetener entries and avoids malformed data.</p>
<h3 id="heading-syrup-schema"><strong>Syrup Schema</strong></h3>
<p>Similar to sweeteners, but for syrup flavors:</p>
<pre><code class="lang-typescript">
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> SyrupSchema = z.object({
  name: z.string(),
  description: z.string(),
  image: z.string().url().optional(),
});
</code></pre>
<p>This can represent flavors like Vanilla, Caramel, or Hazelnut.</p>
<h3 id="heading-topping-schema"><strong>Topping Schema</strong></h3>
<p>Toppings such as whipped cream or cinnamon are defined here.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ToppingSchema = z.object({
  name: z.string(),
  description: z.string(),
  image: z.string().url().optional(),
});
</code></pre>
<h3 id="heading-size-schema"><strong>Size Schema</strong></h3>
<p>Drink sizes are modeled as objects as well:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> SizeSchema = z.object({
  name: z.string(),               <span class="hljs-comment">// e.g. Small, Medium</span>
  description: z.string(),        <span class="hljs-comment">// A short explanation</span>
  image: z.string().url().optional(),
});
</code></pre>
<h3 id="heading-milk-schema"><strong>Milk Schema</strong></h3>
<p>Represents milk types such as Whole, Skim, Almond, or Oat.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> MilkSchema = z.object({
  name: z.string(),
  description: z.string(),
  image: z.string().url().optional(),
});
</code></pre>
<h3 id="heading-collections-of-items"><strong>Collections of Items</strong></h3>
<p>Now that the individual item schemas exist, we can create <strong>collections</strong> of them. These represent all available toppings, sizes, milk types, syrups, sweeteners, and the entire menu of drinks</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ToppingsSchema = z.array(ToppingSchema);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> SizesSchema = z.array(SizeSchema);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> MilksSchema = z.array(MilkSchema);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> SyrupsSchema = z.array(SyrupSchema);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> SweetenersSchema = z.array(SweetenerSchema);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> DrinksSchema = z.array(DrinkSchema);
</code></pre>
<p>Why arrays? Because in the real world, your agent will receive <strong>lists</strong> from a database or API—not single items.</p>
<h3 id="heading-inferred-types"><strong>Inferred Types</strong></h3>
<p>Zod also allows TypeScript to infer types from schemas automatically.</p>
<p>This ensures:</p>
<ul>
<li><p>TypeScript types always match the schemas.</p>
</li>
<li><p>You avoid duplicated definitions.</p>
</li>
<li><p>The agent code stays consistent and safe.</p>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> Drink = z.infer&lt;<span class="hljs-keyword">typeof</span> DrinkSchema&gt;;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> SupportSweetener = z.infer&lt;<span class="hljs-keyword">typeof</span> SweetenerSchema&gt;;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> Syrup = z.infer&lt;<span class="hljs-keyword">typeof</span> SyrupSchema&gt;;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> Topping = z.infer&lt;<span class="hljs-keyword">typeof</span> ToppingSchema&gt;;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> Size = z.infer&lt;<span class="hljs-keyword">typeof</span> SizeSchema&gt;;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> Milk = z.infer&lt;<span class="hljs-keyword">typeof</span> MilkSchema&gt;;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> Toppings = z.infer&lt;<span class="hljs-keyword">typeof</span> ToppingsSchema&gt;;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> Sizes = z.infer&lt;<span class="hljs-keyword">typeof</span> SizesSchema&gt;;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> Milks = z.infer&lt;<span class="hljs-keyword">typeof</span> MilksSchema&gt;;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> Syrups = z.infer&lt;<span class="hljs-keyword">typeof</span> SyrupsSchema&gt;;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> Sweeteners = z.infer&lt;<span class="hljs-keyword">typeof</span> SweetenersSchema&gt;;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> Drinks = z.infer&lt;<span class="hljs-keyword">typeof</span> DrinksSchema&gt;;
</code></pre>
<p>These provide the rest of your LangChain/LangGraph code with strong typing based on your schema definitions.</p>
<p>This entire file:</p>
<ul>
<li><p>Encodes all drink-related data structures.</p>
</li>
<li><p>Provides validation to ensure clean, predictable data.</p>
</li>
<li><p>Automatically generates TypeScript types.</p>
</li>
<li><p>Helps the AI agent reason reliably about drinks and customization options.</p>
</li>
</ul>
<p>You’ll use these schemas later and convert them into string representations for LLM prompts.</p>
<p><em>You can find the file containing all the code</em> <a target="_blank" href="https://github.com/DjibrilM/langgraph-starbucks-agent/blob/main/src/lib/schemas/drinks.ts"><em>here</em></a><em>.</em></p>
<h2 id="heading-how-to-parse-the-schema">How to Parse the Schema</h2>
<p>As mentioned earlier, LLMs are <strong>text input–output machines</strong>. They don’t understand TypeScript types or Zod schemas directly. If you include a schema inside a prompt, the model will simply see it as plain text without understanding its structure or constraints.</p>
<p>Because of this, we need a way to convert schemas into a readable string format that can be embedded inside a prompt, such as:</p>
<blockquote>
<p>“The output must be a JSON object with the following fields…”</p>
</blockquote>
<p>This is exactly the problem solved by <code>StructuredOutputParser</code> from <code>langchain/output_parsers</code>. It takes a Zod schema and turns it into:</p>
<ul>
<li><p>A human-readable description that can be sent to an LLM.</p>
</li>
<li><p>A validator that checks whether the model’s output matches the schema.</p>
</li>
</ul>
<p>In short, it acts as a bridge between typed application logic and text-based AI output.</p>
<h3 id="heading-defining-the-order-schema">Defining the Order Schema</h3>
<p>We’ll start with a simple Zod schema that represents a customer’s drink order. This schema defines the exact shape and constraints of the data we expect the model to produce.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> OrderSchema = z.object({
  drink: z.string(),
  size: z.string(),
  mil: z.string(),
  syrup: z.string(),
  sweeteners: z.string(),
  toppings: z.string(),
  quantity: z.number().min(<span class="hljs-number">1</span>).max(<span class="hljs-number">10</span>),
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> OrderType = z.infer&lt;<span class="hljs-keyword">typeof</span> OrderSchema&gt;;
</code></pre>
<p>At this point, the schema is useful only inside our TypeScript application. The LLM still has no idea what this structure means.</p>
<h3 id="heading-parsing-the-schema-into-human-readable-text">Parsing the Schema into Human-Readable Text</h3>
<p>This is where schema parsing comes in. Using <code>StructuredOutputParser.fromZodSchema</code>, we can transform the Zod schema into:</p>
<ul>
<li><p>Instructions the LLM can understand.</p>
</li>
<li><p>A runtime validator that ensures the response is correct.</p>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> OrderParser =
  StructuredOutputParser.fromZodSchema(OrderSchema <span class="hljs-keyword">as</span> <span class="hljs-built_in">any</span>);
</code></pre>
<p>The parser enables two critical workflows:</p>
<h4 id="heading-generating-prompt-instructions">Generating prompt instructions</h4>
<p>The parser can generate a text description of the schema that looks roughly like: “Return a JSON object with the fields <code>drink</code>, <code>size</code>, <code>mil</code>, <code>syrup</code>, <code>sweeteners</code>, and <code>toppings</code> as strings, and <code>quantity</code> as a number between 1 and 10.” This string can be injected directly into your prompt so the LLM knows exactly how to format its response.</p>
<h4 id="heading-validating-the-models-output">Validating the model’s output</h4>
<p>After the LLM responds, its output is still just text. The parser:</p>
<ul>
<li><p>Converts that text into a JavaScript object.</p>
</li>
<li><p>Validates it against the original Zod schema.</p>
</li>
<li><p>Throws an error if anything is missing, malformed, or out of bounds.</p>
</li>
</ul>
<p>This prevents invalid AI-generated data (for example, <code>quantity: 0</code>) from entering your system.</p>
<h3 id="heading-reusing-the-same-approach-for-other-schemas">Reusing the Same Approach for Other Schemas</h3>
<p>Once you understand this pattern, applying it to other schemas is straightforward.</p>
<p>For example, you can do the same thing for a <code>DrinkSchema</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> DrinkParser =
  StructuredOutputParser.fromZodSchema(DrinkSchema <span class="hljs-keyword">as</span> <span class="hljs-built_in">any</span>);
</code></pre>
<p>Now you can confidently say something like: “Hey Gemini, this is what a drink object looks like—please respond using this structure.”</p>
<h3 id="heading-why-this-matters">Why This Matters</h3>
<p>Schema parsing allows you to:</p>
<ul>
<li><p>Keep strong typing in your application.</p>
</li>
<li><p>Give clear formatting instructions to the LLM.</p>
</li>
<li><p>Safely convert unstructured AI output into validated, production-ready data.</p>
</li>
</ul>
<p>Without this step, working with LLMs at scale becomes unreliable and error-prone.</p>
<h2 id="heading-data-to-text-summarization">Data-to-Text Summarization</h2>
<p>In the context of LLM agents, <strong>data-to-text summarization</strong> means converting structured data—such as objects returned from a database or backend API—into <strong>clear, human-readable strings</strong> that can be embedded directly into prompts.</p>
<p>Even the most advanced LLMs operate purely on text. They don’t reason over JavaScript objects, database rows, or JSON structures in the same way humans or programs do. The clearer and more descriptive your text input is, the more accurate and reliable the model’s output will be.</p>
<p>Because of this, a common and recommended pattern when building LLM-powered systems is:</p>
<p><strong>Fetch structured data → summarize it into natural language → pass the summary into the prompt</strong></p>
<p>To keep this article focused, we’ll store our data in constants instead of querying a real database. The technique is exactly the same whether the data comes from MongoDB, PostgreSQL, or an API.</p>
<h3 id="heading-the-core-idea">The Core Idea</h3>
<p>The goal of data-to-text summarization is simple:</p>
<ul>
<li><p>Take an object with fields and boolean flags</p>
</li>
<li><p>Convert it into a short paragraph that explains what the object represents</p>
</li>
<li><p>Remove ambiguity and guesswork for the LLM</p>
</li>
</ul>
<p>Instead of forcing the model to infer meaning from raw data, we <em>spell it out explicitly</em>.</p>
<h3 id="heading-summarizing-a-drink-object">Summarizing a Drink Object</h3>
<p>Consider the following drink object:</p>
<pre><code class="lang-typescript">{
  name: <span class="hljs-string">'Espresso'</span>,
  description: <span class="hljs-string">'Strong concentrated coffee shot.'</span>,
  supportMilk: <span class="hljs-literal">false</span>,
  supportSweeteners: <span class="hljs-literal">true</span>,
  supportSyrup: <span class="hljs-literal">true</span>,
  supportTopping: <span class="hljs-literal">false</span>,
  supportSize: <span class="hljs-literal">false</span>,
}
</code></pre>
<p>While this structure is easy for developers to understand, it’s not ideal for an LLM prompt. Boolean flags like <code>supportMilk: false</code> require interpretation, which increases the chance of incorrect assumptions.</p>
<p>Instead, we convert this object into a descriptive paragraph:</p>
<p>“A drink named Espresso. It is described as a strong, concentrated coffee shot. It cannot be made with milk. It can be made with sweeteners. It can be made with syrup. It cannot be made with toppings. It cannot be made in different sizes.”</p>
<p>This transformation is exactly what data-to-text summarization provides.</p>
<h3 id="heading-a-standard-summarization-pattern">A Standard Summarization Pattern</h3>
<p>Below is a simplified example of how we convert a <code>Drink</code> object into a readable description.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> createDrinkItemSummary = (drink: Drink): <span class="hljs-function"><span class="hljs-params">string</span> =&gt;</span> {
  <span class="hljs-keyword">const</span> name = <span class="hljs-string">`A drink named <span class="hljs-subst">${drink.name}</span>.`</span>;
  <span class="hljs-keyword">const</span> description = <span class="hljs-string">`It is described as <span class="hljs-subst">${drink.description}</span>.`</span>;

  <span class="hljs-keyword">const</span> milk = drink.supportMilk
    ? <span class="hljs-string">'It can be made with milk.'</span>
    : <span class="hljs-string">'It cannot be made with milk.'</span>;

  <span class="hljs-keyword">const</span> sweeteners = drink.supportSweeteners
    ? <span class="hljs-string">'It can be made with sweeteners.'</span>
    : <span class="hljs-string">'It cannot contain sweeteners.'</span>;

  <span class="hljs-keyword">const</span> syrup = drink.supportSyrup
    ? <span class="hljs-string">'It can be made with syrup.'</span>
    : <span class="hljs-string">'It cannot be made with syrup.'</span>;

  <span class="hljs-keyword">const</span> toppings = drink.supportTopping
    ? <span class="hljs-string">'It can be made with toppings.'</span>
    : <span class="hljs-string">'It cannot be made with toppings.'</span>;

  <span class="hljs-keyword">const</span> size = drink.supportSize
    ? <span class="hljs-string">'It can be made in different sizes.'</span>
    : <span class="hljs-string">'It cannot be made in different sizes.'</span>;

  <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${name}</span> <span class="hljs-subst">${description}</span> <span class="hljs-subst">${milk}</span> <span class="hljs-subst">${sweeteners}</span> <span class="hljs-subst">${syrup}</span> <span class="hljs-subst">${toppings}</span> <span class="hljs-subst">${size}</span>`</span>;
};
</code></pre>
<h3 id="heading-why-this-works-well-for-llms">Why this works well for LLMs</h3>
<ul>
<li><p>Boolean logic is converted into <strong>explicit sentences</strong></p>
</li>
<li><p>Every capability and limitation is clearly stated</p>
</li>
<li><p>The output can be embedded directly into a system or user prompt</p>
</li>
</ul>
<h3 id="heading-summarizing-collections-of-data">Summarizing Collections of Data</h3>
<p>This same approach applies to lists of data such as milks, syrups, toppings, or sizes. Instead of passing an array of objects to the model, we convert them into bullet-style text summaries:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> createSweetenersSummary = (): <span class="hljs-function"><span class="hljs-params">string</span> =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="hljs-string">`Available sweeteners are:
<span class="hljs-subst">${SWEETENERS.map(
  (s) =&gt; <span class="hljs-string">`- <span class="hljs-subst">${s.name}</span>: <span class="hljs-subst">${s.description}</span>`</span>
).join(<span class="hljs-string">'\n'</span>)}</span>`</span>;
};
</code></pre>
<p>This gives the model a <strong>complete, readable overview</strong> of available options without requiring it to interpret raw arrays.</p>
<h3 id="heading-applying-the-same-idea-to-other-domains">Applying the Same Idea to Other Domains</h3>
<p>This pattern is not limited to drinks or menus. It works for <em>any</em> domain. For example, here’s the same summarization technique applied to an object representing a shoe in an online ordering assistant:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> createShoeItemSummary = (shoe: {
  name: <span class="hljs-built_in">string</span>;
  description: <span class="hljs-built_in">string</span>;
  genderCategory: <span class="hljs-built_in">string</span>;
  styleType: <span class="hljs-built_in">string</span>;
  material: <span class="hljs-built_in">string</span>;
  availableInMultipleColors: <span class="hljs-built_in">boolean</span>;
  limitedEdition: <span class="hljs-built_in">boolean</span>;
  supportsCustomization: <span class="hljs-built_in">boolean</span>;
}): <span class="hljs-function"><span class="hljs-params">string</span> =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="hljs-string">`
A shoe named <span class="hljs-subst">${shoe.name}</span>.
It is described as <span class="hljs-subst">${shoe.description}</span>.
It is categorized as a <span class="hljs-subst">${shoe.genderCategory.toLowerCase()}</span> shoe.
It belongs to the <span class="hljs-subst">${shoe.styleType.toLowerCase()}</span> fashion style.
It is made of <span class="hljs-subst">${shoe.material.toLowerCase()}</span> material.
<span class="hljs-subst">${shoe.availableInMultipleColors ? <span class="hljs-string">'It is available in multiple colors.'</span> : <span class="hljs-string">'It is available in a single color.'</span>}</span>
<span class="hljs-subst">${shoe.limitedEdition ? <span class="hljs-string">'It is a limited-edition release.'</span> : <span class="hljs-string">'It is not a limited-edition release.'</span>}</span>
<span class="hljs-subst">${shoe.supportsCustomization ? <span class="hljs-string">'It supports customization options.'</span> : <span class="hljs-string">'It does not support customization options.'</span>}</span>
`</span>.trim();
};
</code></pre>
<p>Which produces an output like:</p>
<p>“A shoe named Veloria Canvas Sneaker. It is described as a minimalist everyday sneaker designed for casual wear. It is categorized as a unisex shoe. It belongs to the casual fashion style. It is made of breathable canvas material. It is available in multiple colors. It is not a limited-edition release. It supports light customization options.”</p>
<h2 id="heading-how-to-persist-orders-with-mongodb-in-nestjs">How to Persist Orders with MongoDB in NestJS</h2>
<p>Now that we’ve established the core foundations of our application—schemas, parsers, and data-to-text summaries—it’s time to <strong>persist data</strong>. In a real-world assistant, orders and conversations shouldn’t disappear when the server restarts. They need to be stored reliably so they can be retrieved, analyzed, or continued later.</p>
<p>To achieve this, we’ll use MongoDB as our database and the NestJS Mongoose integration to manage data models and collections.</p>
<h3 id="heading-connecting-mongodb-to-a-nestjs-application">Connecting MongoDB to a NestJS Application</h3>
<p>In NestJS, the <code>AppModule</code> is the root module of the application. This is where global dependencies—such as database connections—are configured.</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@Module</span>({
  imports: [
    MongooseModule.forRoot(process.env.MONGO_URI),
    ChatsModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule {}
</code></pre>
<p>What’s happening here?</p>
<ul>
<li><p><code>MongooseModule.forRoot(...)</code> establishes a global MongoDB connection.</p>
</li>
<li><p>The connection string is read from an environment variable (<code>MONGO_URI</code>), which is the recommended practice for security.</p>
</li>
<li><p>Once configured, this connection becomes available throughout the entire application.</p>
</li>
<li><p><code>ChatsModule</code> is imported so it can access the database connection and register its own schemas.</p>
</li>
</ul>
<p>This setup ensures that every feature module can safely interact with MongoDB without creating multiple connections.</p>
<h3 id="heading-defining-an-order-schema-with-mongoose">Defining an Order Schema with Mongoose</h3>
<p>NestJS uses decorators to define MongoDB schemas in a clean, class-based way. Each class represents a MongoDB document, and each property becomes a field in the collection.</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@Schema</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> Order {
  <span class="hljs-meta">@Prop</span>({ required: <span class="hljs-literal">true</span> })
  drink: <span class="hljs-built_in">string</span>;

  <span class="hljs-meta">@Prop</span>({ <span class="hljs-keyword">default</span>: <span class="hljs-literal">null</span> })
  size: <span class="hljs-built_in">string</span>;

  <span class="hljs-meta">@Prop</span>({ <span class="hljs-keyword">default</span>: <span class="hljs-literal">null</span> })
  milk: <span class="hljs-built_in">string</span>;

  <span class="hljs-meta">@Prop</span>({ <span class="hljs-keyword">default</span>: <span class="hljs-literal">null</span> })
  syrup: <span class="hljs-built_in">string</span>;

  <span class="hljs-meta">@Prop</span>({ <span class="hljs-keyword">default</span>: <span class="hljs-literal">null</span> })
  sweeter: <span class="hljs-built_in">string</span>;

  <span class="hljs-meta">@Prop</span>({ <span class="hljs-keyword">default</span>: <span class="hljs-literal">null</span> })
  toppings: <span class="hljs-built_in">string</span>;

  <span class="hljs-meta">@Prop</span>({ <span class="hljs-keyword">default</span>: <span class="hljs-number">1</span> })
  quantity: <span class="hljs-built_in">number</span>;
}
</code></pre>
<p>Why this approach?</p>
<ul>
<li><p>Each <code>@Prop()</code> decorator maps directly to a MongoDB field.</p>
</li>
<li><p>Default values allow partial orders to be saved incrementally.</p>
</li>
<li><p>Required fields (like <code>drink</code>) enforce basic data integrity.</p>
</li>
<li><p>The schema closely mirrors the structured output produced by the LLM.</p>
</li>
</ul>
<p>Once the class is defined, it’s converted into a MongoDB schema:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> OrderSchema = SchemaFactory.createForClass(Order);
</code></pre>
<p>This single line creates:</p>
<ul>
<li><p>A MongoDB collection</p>
</li>
<li><p>A validation layer</p>
</li>
<li><p>A schema that Mongoose can use to create, read, and update orders</p>
</li>
</ul>
<h3 id="heading-how-this-fits-into-the-llm-agent-architecture">How This Fits into the LLM Agent Architecture</h3>
<p>At this point, we have:</p>
<ul>
<li><p><strong>Zod schemas</strong> → for validating AI output</p>
</li>
<li><p><strong>Summarization functions</strong> → for converting data into readable prompts</p>
</li>
<li><p><strong>MongoDB schemas</strong> → for persisting finalized orders</p>
</li>
</ul>
<p>This separation is intentional:</p>
<ul>
<li><p>Zod handles <em>AI-facing validation</em></p>
</li>
<li><p>Mongoose handles <em>database persistence</em></p>
</li>
<li><p>NestJS acts as the glue that ties everything together</p>
</li>
</ul>
<h3 id="heading-preparing-for-the-agent-logic">Preparing for the Agent Logic</h3>
<p>With the database in place, we’re now ready to implement the agent itself.</p>
<p>The agent’s responsibilities will include:</p>
<ul>
<li><p>Interpreting user messages</p>
</li>
<li><p>Calling tools</p>
</li>
<li><p>Generating structured orders</p>
</li>
<li><p>Validating them</p>
</li>
<li><p>Persisting them to MongoDB</p>
</li>
<li><p>Maintaining conversational state</p>
</li>
</ul>
<p>All of this logic will live inside the <code>src/chats/chats.service.ts</code> file. The next section introduces the <strong>agent’s core logic</strong>, and we’ll walk through it step by step so every part is easy to follow.</p>
<p>Start by importing the required dependencies:</p>
<pre><code class="lang-tsx">
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { MongoClient } from 'mongodb';
import { Model } from 'mongoose';

import { tool } from '@langchain/core/tools';
import {
  ChatPromptTemplate,
  MessagesPlaceholder,
} from '@langchain/core/prompts';
import { AIMessage, BaseMessage, HumanMessage } from '@langchain/core/messages';

import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
import { StateGraph } from '@langchain/langgraph';
import { ToolNode } from '@langchain/langgraph/prebuilt';
import { Annotation } from '@langchain/langgraph';
import { START, END } from '@langchain/langgraph';

import { MongoDBSaver } from '@langchain/langgraph-checkpoint-mongodb';

import z from 'zod';

import { Order } from './schemas/order.schema';
import { OrderParser, OrderSchema, OrderType } from 'src/lib/schemas/orders';
import { DrinkParser } from 'src/lib/schemas/drinks';
import { DRINKS } from 'src/lib/utils/constants/menu_data';

import {
  createSweetenersSummary,
  availableToppingsSummary,
  createAvailableMilksSummary,
  createSyrupsSummary,
  createSizesSummary,
  createDrinkItemSummary,
} from 'src/lib/summaries';

const GOOGLE_API_KEY = process.env.GOOGLE_API_KEY || '';
const client: MongoClient = new MongoClient(process.env.MONGO_URI || '');
const database_name = 'drinks_db';
</code></pre>
<h2 id="heading-langgraph-stateannotation-terms">LangGraph State/Annotation Terms</h2>
<p>In LangGraph, <strong>state</strong> can be thought of as a temporary workspace that exists while the agent is running. It stores all the information that nodes (we’ll cover nodes in detail later) might need to access information like the last message, the history of the conversation, or any intermediate data generated during execution.</p>
<p>This state allows nodes to <strong>read from it, update it, and pass information along</strong> as the agent processes a workflow, making it the agent’s short-term memory for the duration of the run.</p>
<pre><code class="lang-tsx">@Injectable()
export class ChatService {

  chatWithAgent = async ({
    thread_id,
    query,
  }: {
    thread_id: string;
    query: string;
  }) =&gt; {

    const graphState = Annotation.Root({
      messages: Annotation&lt;BaseMessage[]&gt;({
        reducer: (x, y) =&gt; [...x, ...y],
      }),
    });

  }

}
</code></pre>
<p>This code defines the <strong>LangGraph state</strong> for the chat agent. The <code>graphState</code> object acts as a central memory that every node in the workflow can read from and update.</p>
<p>The <code>messages</code> field specifically stores all messages in the conversation, including user messages, AI responses, and tool outputs. The reducer function <code>[...x, ...y]</code> appends new messages to the existing array, preserving the conversation history across multiple steps.</p>
<p>LangGraph’s reducer mechanism lets developers control how new state merges with old state. In this chat system, the approach is similar to updating React state with <code>setMessages(prev =&gt; [...prev, ...newMessages])</code>: it keeps the old messages while adding the new ones.</p>
<p>Together, this state enables the agent, tools, and checkpointing system to maintain a coherent conversation, allowing each node in the LangGraph workflow to access the full context and contribute incrementally.</p>
<h2 id="heading-how-to-create-tools-for-the-agent">How to Create Tools for the Agent</h2>
<p>Modern chatbots can do more than just generate text - they can also search the internet, read files, or perform computations. While LLMs are powerful, they cannot execute code or compile programs on their own.</p>
<p>In the code text of LLM agents, a tool is a piece of code written by the agent developer that an LLM can invoke on the host machine. The host machine executes the code, and the LLM only receives the final output of the computation.</p>
<p>Here's how to create a tool that stores orders in the database. Still in the <code>chatWithAgent</code> function within the <code>ChatService</code> class. Bellow the state store definition:</p>
<pre><code class="lang-tsx">const orderTool = tool(
  async ({ order }: { order: OrderType }) =&gt; {
    try {
      await this.orderModel.create(order);
      return 'Order created successfully';
    } catch (error) {
      console.log(error);
      return 'Failed to create the order';
    }
  },
  {
    schema: z.object({
      order: OrderSchema.describe('The order that will be stored in the DB'),
    }),
    name: 'create_order',
    description: 'This tool creates a new order in the database',
  }
);

const tools = [orderTool];
</code></pre>
<h2 id="heading-langgraph-nodes-workflow-components">LangGraph Nodes (Workflow Components)</h2>
<p>From a definition standpoint, a LangGraph node is a fundamental component of a LangGraph workflow, representing a single unit of computation or an individual step in an AI agent's process.</p>
<p>Each node can perform a specific task, such as generating a message, invoking a tool, or transforming data, and it interacts with the state to read inputs and write outputs. Together, nodes are connected to form the agent’s workflow or execution graph, allowing complex reasoning and multi-step operations.</p>
<p>In our project, we’ll have four nodes.</p>
<ol>
<li><p><strong>Agent node:</strong> This node is in charge of interacting with the LLM - it constructs the agent’s main message template and stacks old messages to the new prompt to create context.</p>
</li>
<li><p><strong>Tools node:</strong> The tools node introduces external capabilities, which allow the workflow to interact with external APIs</p>
</li>
<li><p><code>START</code> <strong>node:</strong> This node indicates the entry point of our workflow, or to be precise, which node to call when a user initiates a conversation with the agent. It’s quite simple to define.</p>
</li>
<li><p><code>addConditionalEdges</code> - <code>addConditionalEdges('agent', shouldContinue)</code>: In LangGraph, <code>.addConditionalEdges('agent', shouldContinue)</code> lets the workflow branch dynamically after the <code>'agent'</code> node runs, based on a condition defined in <code>shouldContinue</code>. Unlike a fixed edge, which always goes from one node to the next, a conditional edge evaluates the agent’s output and directs the workflow to different nodes depending on the result, allowing the AI agent to make decisions and adapt its next steps.</p>
</li>
</ol>
<h2 id="heading-graph-declaration">Graph Declaration</h2>
<p>In LangGraph, a graph is the central structure that models an AI agent’s workflow as interconnected nodes, where each node represents a computation step, tool, or decision. It orchestrates the flow of data and control between nodes, manages conditional branching, and maintains the recursive loop of execution.</p>
<p>Essentially, the graph is the backbone that ensures complex, stateful interactions happen in a coordinated and modular way, connecting nodes like <code>agent</code>, <code>tools</code>, and conditional edges into a coherent workflow.</p>
<p>With that knowledge in place, we can now create the agent graph with all its nodes.</p>
<pre><code class="lang-tsx">  const callModal = async (states: typeof graphState.State) =&gt; {
    const prompt = ChatPromptTemplate.fromMessages([
      {
        role: 'system',
        content: `
            You are a helpful assistant that helps users order drinks from Starbucks.
            Your job is to take the user's request and fill in any missing details based on how a complete order should look.
            A complete order follows this structure: ${OrderParser}.

            **TOOLS**
            You have access to a "create_order" tool.
            Use this tool when the user confirms the final order.
            After calling the tool, you should inform the user whether the order was successfully created or if it failed.

            **DRINK DETAILS**
            Each drink has its own set of properties such as size, milk, syrup, sweetener, and toppings.
            Here is the drink schema: ${DrinkParser}.

            You must ask for any missing details before creating the order.

            If the user requests a modification that is not supported for the selected drink, tell them that it is not possible.

            If the user asks for something unrelated to drink orders, politely tell them that you can only assist with drink orders.

            **AVAILABLE OPTIONS**
            List of available drinks and their allowed modifications:
            ${DRINKS.map((drink) =&gt; `- ${createDrinkItemSummary(drink)}`)}

            Sweeteners: ${createSweetenersSummary()}
            Toppings: ${availableToppingsSummary()}
            Milks: ${createAvailableMilksSummary()}
            Syrups: ${createSyrupsSummary()}
            Sizes: ${createSizesSummary()}

            Order schema: ${OrderParser}

            If the user's query is unclear, tell them that the request is not clear.

            **ORDER CONFIRMATION**
            Once the order is ready, you must ask the user to confirm it.
            If they confirm, immediately call the "create_order" tool.
            Only respond after the tool completes, indicating success or failure.

            **FRONTEND RESPONSE FORMAT**
            Every response must include:

            "message": "Your message to the user",
            "current_order": "The order currently being constructed",
            "suggestions": "Options the user can choose from",
            "progress": "Order status ('completed' after creation)"

            **IMPORTANT RULES**
            - Be friendly, use emojis, and add humor.
            - Use null for unfilled fields.
            - Never omit the JSON tracking object.
        `,
      },
      new MessagesPlaceholder('messages'),
    ]);

  const formattedPrompt = await prompt.formatMessages({
    time: new Date().toISOString(),
    messages: states.messages,
  });

  const chat = new ChatGoogleGenerativeAI({
    model: 'gemini-2.0-flash',
    temperature: 0,
    apiKey: GOOGLE_API_KEY,
  }).bindTools(tools);

  const result = await chat.invoke(formattedPrompt);
  return { messages: [result] };
  };     
    const shouldContinue = (state: typeof graphState.State) =&gt; {
      const lastMessage = state.messages[
        state.messages.length - 1
      ] as AIMessage;
      return lastMessage.tool_calls?.length ? 'tools' : END;
    };

    const toolsNode = new ToolNode&lt;typeof graphState.State&gt;(tools);

    /**
     * Build the conversation graph.
     */
    const graph = new StateGraph(graphState)
      .addNode('agent', callModal)
      .addNode('tools', toolsNode)
      .addEdge(START, 'agent')
      .addConditionalEdges('agent', shouldContinue)
      .addEdge('tools', 'agent');
</code></pre>
<h3 id="heading-explanation">Explanation</h3>
<ul>
<li><p><strong>Graph State (</strong><code>graphState</code>)<br>  The <code>graphState</code> object is the shared memory across all nodes. It stores <code>messages</code>, which track the conversation history including user inputs, AI responses, and tool interactions. The reducer <code>[...x, ...y]</code> appends new messages, preserving past context. This is similar to React state updates: old messages remain while new ones are added.</p>
</li>
<li><p><strong>Agent Node (</strong><code>callModal</code>)<br>  This node handles the <strong>LLM call</strong>. It formats a prompt containing system instructions, drink schemas, available tools, and frontend response rules. By including <code>states.messages</code>, the AI sees the full conversation history, enabling multi-turn dialogue.</p>
</li>
<li><p><strong>LLM Execution</strong><br>  <code>ChatGoogleGenerativeAI</code> generates the AI response. <code>.bindTools(tools)</code> allows the AI to call tools like <code>create_order</code> directly if needed.</p>
</li>
<li><p><strong>Conditional Flow (</strong><code>shouldContinue</code>)<br>  After the AI responds, the <code>shouldContinue</code> function checks if the message includes tool calls. If so, execution moves to the <code>tools</code> node; otherwise, the workflow ends. This allows dynamic branching depending on the AI’s output.</p>
</li>
<li><p><strong>Tool Node (</strong><code>ToolNode</code>)<br>  The <code>tools</code> node executes the requested tool, such as saving the order to the database. Once completed, control returns to the agent node, enabling the AI to respond to the user with results.</p>
</li>
<li><p><strong>Graph Construction (</strong><code>StateGraph</code>)<br>  Nodes are connected in a coherent workflow:</p>
<ul>
<li><p><code>START → agent</code> begins the conversation</p>
</li>
<li><p>Conditional edges handle tool execution</p>
</li>
<li><p><code>tools → agent</code> ensures the agent can respond after tools run</p>
</li>
</ul>
</li>
<li><p><strong>Overall Flow</strong><br>  Together, the graph and shared state ensure a <strong>stateful, multi-turn conversation</strong>. The AI can ask for missing details, call tools when needed, and maintain context across interactions. Every node reads and writes to the same state.</p>
</li>
</ul>
<h2 id="heading-workflow-compilation-and-state-persistence-final-part"><strong>Workflow Compilation and State Persistence (Final Part)</strong></h2>
<p>So far, all of our states are temporary, meaning they only exist for the duration of a user’s request. However, we want our agent to <strong>remember and recall conversation context</strong> even when a new request is sent with the same <code>thread_id</code> or conversation ID.</p>
<p>To achieve this, we’ll use MongoDB in combination with the <code>langchain/langgraph-checkpoint-mongo</code> library. This library simplifies state persistence by associating each conversation with a unique, manually assigned ID. All operations—from retrieving previous messages to saving new ones—are handled internally, you only need to provide the conversation ID you want to work with.</p>
<pre><code class="lang-tsx">const graph = new StateGraph(graphState)
  .addNode('agent', callModal)
  .addNode('tools', toolsNode)
  .addEdge(START, 'agent')
  .addConditionalEdges('agent', shouldContinue)
  .addEdge('tools', 'agent');

  const checkpointer = new MongoDBSaver({ client, dbName: database_name });

  const app = graph.compile({ checkpointer });

  /**
     * Run the graph using the user's message.
     */
    const finalState = await app.invoke(
      { messages: [new HumanMessage(query)] },
      { recursionLimit: 15, configurable: { thread_id } },
    );

  /**
   * Extract JSON payload from AI response.
   */
  function extractJsonResponse(response: any) {
    const match = response.match(/```json\\s*([\\s\\S]*?)\\s*```/i);
    if (match &amp;&amp; match[1] &amp;&amp; typeof response === 'string') {
      return JSON.parse(match[1].trim());
    }
    throw response;
  }

  const lastMessage = finalState.messages.at(-1) as AIMessage; // Extract the last message of the conversation
  return extractJsonResponse(lastMessage.content); //Response
</code></pre>
<p>The above code demonstrates how to initialize a checkpoint, compile a graph, and invoke the agent with an incoming prompt.</p>
<p>The <code>extractJsonResponse</code> method is used to grab the formatted response that we instructed the LLM to generate whenever it’s sending back something to the user.</p>
<p>Based on this given instruction from the main template, every response must include: "message": "Your message to the user", "current_order": "The order currently being constructed", "suggestions": "Options the user can choose from", "progress": "Order status ('completed' after creation)"</p>
<p>Every response from the LLM should look like this:</p>
<pre><code class="lang-tsx">'```json\\n' +
  '{\\n' +
  '"message": "Got it! To make sure I get your order just right, can you clarify which coffee drink you\\'d like? We have Latte, Cappuccino, Cold Brew, and Frappuccino. 😊",\\n' +
  '"current_order": {\\n' +
  '"drink": null,\\n' +
  '"size": null,\\n' +
  '"mil": null,\\n' +
  '"syrup": null,\\n' +
  '"sweeteners": null,\\n' +
  '"toppings": null,\\n' +
  '"quantity": null\\n' +
  '},\\n' +
  '"suggestions": [\\n' +
  '"Latte",\\n' +
  '"Cappuccino",\\n' +
  '"Cold Brew",\\n' +
  '"Frappuccino"\\n' +
  '],\\n' +
  '"progress": "incomplete"\\n' +
  '}\\n' +
  '```';
</code></pre>
<p>This structure allows the frontend to easily render the LLM response and track the state of the current order. This is more of a design choice and less of a convention.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Building an autonomous AI agent with LangChain and LangGraph allows you to combine the reasoning power of LLMs with practical tool execution and persistent memory. By defining schemas, parsing data into human-readable formats, and orchestrating workflows through nodes, you can create intelligent agents capable of handling real-world tasks—like our Starbucks barista.</p>
<p>With MongoDB integration for state persistence, your agent can maintain context across conversations, making interactions feel more natural and human-like. This approach opens the door to building more sophisticated, domain-specific AI assistants without starting from scratch.</p>
<p>In short: <strong>define your data, teach your agent how to reason, and let LangGraph orchestrate the magic.</strong> ☕🤖</p>
<p>Source code here: <a target="_blank" href="https://github.com/DjibrilM/langgraph-starbucks-agent">https://github.com/DjibrilM/langgraph-starbucks-agent</a></p>
<h3 id="heading-resources"><strong>Resources</strong></h3>
<ul>
<li><p>LangGraph documentation: <a target="_blank" href="https://docs.langchain.com/oss/javascript/langgraph/quickstart">https://docs.langchain.com/oss/javascript/langgraph/quickstart</a></p>
</li>
<li><p>Synergizing Reasoning and Acting in Language Models: <a target="_blank" href="https://arxiv.org/abs/2210.03629">https://arxiv.org/abs/2210.03629</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn NestJS for Beginners ]]>
                </title>
                <description>
                    <![CDATA[ NestJS is a progressive Node.js framework for building efficient and reliable server-side applications. It uses TypeScript by default and encourages clean, modular code with concepts including controllers, services, and dependency injection. We just ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-nestjs-for-beginners/</link>
                <guid isPermaLink="false">692f67007fa18557e4b8ce73</guid>
                
                    <category>
                        <![CDATA[ nestjs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Tue, 02 Dec 2025 22:24:00 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1764714228452/cd896109-228c-4060-b596-2bb072058976.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>NestJS is a progressive Node.js framework for building efficient and reliable server-side applications. It uses TypeScript by default and encourages clean, modular code with concepts including controllers, services, and dependency injection.</p>
<p>We just published a NestJS course on the freeCodeCamp.org YouTube channel that will help you harness it’s modular architecture, TypeScript support, and built-in tools to create clean, testable, code.</p>
<p>In this course, you'll explore controllers, services, modules, decorators, pipes, guards, and exception handling - all while building the profile feature for DevMatch, a dating app for developers.</p>
<p>You’ll implement profile creation, updates, and data retrieval while exploring the full lifecycle of a NestJS backend. By the end, you’ll have a solid foundation in NestJS fundamentals, plus the confidence to apply these skills to your own APIs and applications.</p>
<p>The course covers:</p>
<ul>
<li><p>Understand NestJS fundamentals: modules, decorators, and structure.</p>
</li>
<li><p>Build controllers to handle GET, POST, PUT, and DELETE requests.</p>
</li>
<li><p>Connect controllers to services to manage application logic.</p>
</li>
<li><p>Implement validation and transformation with pipes.</p>
</li>
<li><p>Handle errors gracefully with exception filters.</p>
</li>
<li><p>Use guards to manage application security and access control.</p>
</li>
<li><p>Solve hands-on challenges that reinforce each concept.</p>
</li>
</ul>
<p>Watch the full course on the <a target="_blank" href="https://youtu.be/21_I-12f5JE">freeCodeCamp.org YouTube channel</a> (2-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/21_I-12f5JE" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The NestJS Handbook – Learn to Use Nest with Code Examples ]]>
                </title>
                <description>
                    <![CDATA[ NestJS is a progressive Node.js framework for building efficient, reliable, and scalable server-side applications. Combining the best ideas from OOP (Object-Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming)... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/the-nestjs-handbook-learn-to-use-nest-with-code-examples/</link>
                <guid isPermaLink="false">684c867db87f779c97f2e509</guid>
                
                    <category>
                        <![CDATA[ nestjs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ German Cocca ]]>
                </dc:creator>
                <pubDate>Fri, 13 Jun 2025 20:13:49 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1749830137752/799b050a-f884-4043-9db1-fe2bb860d297.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>NestJS is a progressive Node.js framework for building efficient, reliable, and scalable server-side applications. Combining the best ideas from OOP (Object-Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming), it gives you a fully-architected, batteries-included platform on top of Express (or Fastify).</p>
<p>If you’re coming from Angular, you’ll feel right at home with its module/controller/service structure and powerful dependency-injection system.</p>
<p>In this article we’ll cover both <strong>theory</strong> – why NestJS exists, how it’s structured, and when to reach for it –and <strong>practice</strong>, with bite-sized code snippets demonstrating how to bootstrap a project, define routes, inject dependencies, and more. Let’s start by understanding what NestJS is and where it came from.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-1-what-is-nestjs">What is NestJS?</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-11-history-and-philosophy">1.1 History and Philosophy</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-2-why-choose-nestjs">Why Choose NestJS?</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-21-benefits-and-use-cases">2.1 Benefits and Use Cases</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-22-comparison-with-other-frameworks">2.2 Comparison with Other Frameworks</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-3-getting-started">Getting Started</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-31-installing-the-cli">3.1 Installing the CLI</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-32-creating-your-first-project">3.2 Creating Your First Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-33-project-structure-overview">3.3 Project Structure Overview</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-4-core-nestjs-building-blocks">Core NestJS Building Blocks</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-41-modules">4.1 Modules</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-42-controllers">4.2 Controllers</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-43-providers-services">4.3 Providers (Services)</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-5-dependency-injection">Dependency Injection</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-51-how-di-works-in-nestjs">5.1 How DI Works in NestJS</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-52-custom-providers-and-factory-providers">5.2 Custom Providers and Factory Providers</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-6-routing-amp-middleware">Routing &amp; Middleware</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-61-defining-routes">6.1 Defining Routes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-62-applying-middleware">6.2 Applying Middleware</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-7-request-lifecycle-amp-pipes">Request Lifecycle &amp; Pipes</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-71-what-are-pipes">7.1 What Are Pipes?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-72-built-in-vs-custom-pipes">7.2 Built-In vs. Custom Pipes</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-8-guards-amp-authorization">Guards &amp; Authorization</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-81-implementing-guards">8.1 Implementing Guards</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-82-role-based-access-control">8.2 Role-Based Access Control</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-9-exception-filters">Exception Filters</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-91-handling-errors-gracefully">9.1 Handling Errors Gracefully</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-92-creating-custom-filters">9.2 Creating Custom Filters</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-10-interceptors-amp-logging">Interceptors &amp; Logging</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-101-transforming-responses">10.1 Transforming Responses</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-102-logging-and-performance-metrics">10.2 Logging and Performance Metrics</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-11-database-integration">Database Integration</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-111-typeorm-with-nestjs">11.1 TypeORM with NestJS</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-112-mongoose-mongodb">11.2 Mongoose (MongoDB)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-113-prisma">11.3 Prisma</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-12-configuration-management">Configuration Management</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-121-nestjsconfig-module">12.1 @nestjs/config Module</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-122-environment-variables">12.2 Environment Variables</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-13-authentication">Authentication</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-131-jwt-strategy">13.1 JWT Strategy</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-132-oauth2-social-login">13.2 OAuth2 / Social Login</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion-amp-further-resources">Conclusion &amp; Further Resources</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-summary">Summary</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-official-docs-and-community-links">Official Docs and Community Links</a></p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-1-what-is-nestjs">1. What is NestJS?</h2>
<p>NestJS is a framework for building server-side applications in Node.js. It’s written in TypeScript (but supports plain JavaScript as well). At its core, it:</p>
<ul>
<li><p><strong>Wraps</strong> a mature HTTP server library (Express or Fastify)</p>
</li>
<li><p><strong>Standardizes</strong> application architecture around modules, controllers, and providers</p>
</li>
<li><p><strong>Leverages</strong> TypeScript’s type system for compile-time safety and clear APIs</p>
</li>
<li><p><strong>Offers</strong> built-in support for things like validation, configuration, and testing</p>
</li>
</ul>
<p>Rather than stitching together middleware by hand, NestJS encourages a declarative, layered approach. You define <strong>modules</strong> to group related functionality, <strong>controllers</strong> to handle incoming requests, and <strong>providers</strong> (often called “services”) for your business logic. Behind the scenes, NestJS resolves dependencies via an IoC container, so you can focus on writing clean, reusable classes.</p>
<p>To start up a project, run the following commands:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Install the Nest CLI globally</span>
npm install -g @nestjs/cli

<span class="hljs-comment"># Create a new project called 'my-app'</span>
nest new my-app

<span class="hljs-built_in">cd</span> my-app
npm run start:dev
</code></pre>
<p>Once it’s running, you have a ready-to-go HTTP server with hot reloading, strict typing, and a sensible folder layout.</p>
<h3 id="heading-11-history-and-philosophy">1.1 History and Philosophy</h3>
<p>NestJS first appeared in 2017, created by Kamil Myśliwiec. Its goal was to bring the architectural patterns of Angular to the backend world, providing:</p>
<ol>
<li><p><strong>Consistency:</strong> A single, opinionated way to structure applications.</p>
</li>
<li><p><strong>Scalability:</strong> Clear boundaries (modules) make it easier to grow teams and codebases.</p>
</li>
<li><p><strong>Testability:</strong> Built-in support for Jest and clear separation of concerns.</p>
</li>
<li><p><strong>Extensibility:</strong> A pluggable module system makes it easy to integrate ORMs, WebSockets, GraphQL, microservices, and more.</p>
</li>
</ol>
<p>Under the hood, NestJS embraces these principles:</p>
<ul>
<li><p><strong>Modularity:</strong> Everything lives in a module (<code>AppModule</code>, <code>UsersModule</code>, and so on), which can import other modules or export providers.</p>
</li>
<li><p><strong>Dependency Injection:</strong> Services can be injected into controllers (and even into other services), which fosters loose coupling.</p>
</li>
<li><p><strong>Decorators and Metadata:</strong> With TypeScript decorators (<code>@Module()</code>, <code>@Controller()</code>, <code>@Injectable()</code>), NestJS reads metadata at runtime to wire everything together.</p>
</li>
</ul>
<p>Here’s a tiny example showing the interplay of these pieces:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// users.service.ts</span>
<span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersService {
  <span class="hljs-keyword">private</span> users = [{ id: <span class="hljs-number">1</span>, name: <span class="hljs-string">'Alice'</span> }];
  findAll() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.users;
  }
}

<span class="hljs-comment">// users.controller.ts</span>
<span class="hljs-keyword">import</span> { Controller, Get } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.service'</span>;

<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'users'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersController {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> usersService: UsersService</span>) {}

  <span class="hljs-meta">@Get</span>()
  getUsers() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.usersService.findAll();
  }
}

<span class="hljs-comment">// users.module.ts</span>
<span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { UsersController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.controller'</span>;
<span class="hljs-keyword">import</span> { UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.service'</span>;

<span class="hljs-meta">@Module</span>({
  controllers: [UsersController],
  providers: [UsersService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersModule {}
</code></pre>
<ul>
<li><p>The <code>@Module</code> decorator groups controller + service</p>
</li>
<li><p>The controller injects the service via its constructor</p>
</li>
<li><p>A simple <code>GET /users</code> route returns an array of user objects</p>
</li>
</ul>
<p>With that foundation laid, in the next section we’ll explore <strong>why you’d choose NestJS</strong>, comparing it to other popular Node frameworks and outlining common real-world use cases.</p>
<h2 id="heading-2-why-choose-nestjs">2. Why Choose NestJS?</h2>
<p>NestJS isn’t just another Node.js framework – it brings a structured, enterprise-grade approach to building backend services. In this section we’ll cover benefits and real-world use cases, then compare NestJS to other popular Node frameworks so you can see where it fits best.</p>
<h3 id="heading-21-benefits-and-use-cases">2.1 Benefits and Use Cases</h3>
<ol>
<li><p><strong>Strong architectural patterns</strong></p>
<ul>
<li><p><strong>Modularity:</strong> You break your app into focused modules (<code>AuthModule</code>, <code>ProductsModule</code>, and so on), each responsible for a slice of functionality.</p>
</li>
<li><p><strong>Separation of concerns:</strong> Controllers handle HTTP, services encapsulate business logic, modules wire everything up.</p>
</li>
<li><p><strong>Scalability:</strong> Growing teams map naturally onto modules—new features rarely touch existing code.</p>
</li>
</ul>
</li>
<li><p><strong>Built-in dependency injection (DI)</strong></p>
<ul>
<li><p>DI makes testing and swapping implementations trivial.</p>
</li>
<li><p>You can easily mock a service in a unit test:</p>
</li>
</ul>
</li>
</ol>
<pre><code class="lang-typescript">    <span class="hljs-comment">// products.controller.spec.ts</span>
    <span class="hljs-keyword">import</span> { Test, TestingModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/testing'</span>;
    <span class="hljs-keyword">import</span> { ProductsController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./products.controller'</span>;
    <span class="hljs-keyword">import</span> { ProductsService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./products.service'</span>;

    describe(<span class="hljs-string">'ProductsController'</span>, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-keyword">let</span> controller: ProductsController;
      <span class="hljs-keyword">const</span> mockService = { findAll: <span class="hljs-function">() =&gt;</span> [<span class="hljs-string">'apple'</span>, <span class="hljs-string">'banana'</span>] };

      beforeEach(<span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-keyword">const</span> <span class="hljs-keyword">module</span>: TestingModule = await Test.createTestingModule({
          controllers: [ProductsController],
          providers: [
            { provide: ProductsService, useValue: mockService },
          ],
        }).compile();

        controller = <span class="hljs-built_in">module</span>.get&lt;ProductsController&gt;(ProductsController);
      });

      it(<span class="hljs-string">'returns a list of products'</span>, <span class="hljs-function">() =&gt;</span> {
        expect(controller.getAll()).toEqual([<span class="hljs-string">'apple'</span>, <span class="hljs-string">'banana'</span>]);
      });
    });
</code></pre>
<ol start="3">
<li><p><strong>TypeScript-first</strong></p>
<ul>
<li><p>Full type safety at compile time.</p>
</li>
<li><p>Leverage interfaces and decorators (<code>@Body()</code>, <code>@Param()</code>) to validate and transform data.</p>
</li>
</ul>
</li>
<li><p><strong>Rich ecosystem and extensibility</strong></p>
<ul>
<li><p>Official integrations for WebSockets, GraphQL, microservices (RabbitMQ, Kafka), and more.</p>
</li>
<li><p>Hundreds of community modules (for example <code>@nestjs/swagger</code> for OpenAPI docs).</p>
</li>
</ul>
</li>
<li><p><strong>Production-grade tooling</strong></p>
<ul>
<li><p>CLI generates boilerplate (<code>nest g module</code>, <code>nest g service</code>).</p>
</li>
<li><p>Support for hot-reload in development (<code>npm run start:dev</code>).</p>
</li>
<li><p>Built-in testing setup with Jest.</p>
</li>
</ul>
</li>
</ol>
<p><strong>Real-World Use Cases:</strong></p>
<ul>
<li><p><strong>Enterprise APIs</strong> with strict module boundaries and RBAC.</p>
</li>
<li><p><strong>Microservices architectures</strong>, where each service is a self-contained NestJS app.</p>
</li>
<li><p><strong>Real-time applications</strong> (chat, live dashboards) using Nest’s WebSocket gateways.</p>
</li>
<li><p><strong>GraphQL backends</strong> with code-first schemas.</p>
</li>
<li><p><strong>Event-driven systems</strong> connecting to message brokers.</p>
</li>
</ul>
<h3 id="heading-22-comparison-with-other-frameworks">2.2 Comparison with Other Frameworks</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Feature</td><td>Express</td><td>Koa</td><td>NestJS</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Architecture</strong></td><td>Minimal, unopinionated</td><td>Minimal, middleware-based</td><td>Opinionated modules/controllers/services</td></tr>
<tr>
<td><strong>Dependency Injection</strong></td><td>Manual wiring</td><td>Manual wiring</td><td>Built-in, reflect-metadata</td></tr>
<tr>
<td><strong>TypeScript Support</strong></td><td>Via DefinitelyTyped</td><td>Via DefinitelyTyped</td><td>First-class, decorators</td></tr>
<tr>
<td><strong>CLI Tooling</strong></td><td>None (3rd-party)</td><td>None</td><td><code>@nestjs/cli</code> generates code</td></tr>
<tr>
<td><strong>Testing</strong></td><td>User-configured</td><td>User-configured</td><td>Jest + DI makes mocking easy</td></tr>
<tr>
<td><strong>Ecosystem</strong></td><td>Middleware library</td><td>Middleware library</td><td>Official microservices, GraphQL, Swagger modules</td></tr>
<tr>
<td><strong>Learning Curve</strong></td><td>Low</td><td>Low</td><td>Medium (learning Nest idioms)</td></tr>
</tbody>
</table>
</div><ul>
<li><p><strong>Express</strong> is great if you want minimal layers and full control, but you’ll end up hand-rolling a lot (DI, validation, folder structure).</p>
</li>
<li><p><strong>Koa</strong> offers a more modern middleware approach, but still leaves architecture decisions to you.</p>
</li>
<li><p><strong>NestJS</strong> provides the full stack: structure, DI, validation, testing, and official integrations, which is ideal if you value <strong>consistency</strong>, <strong>type safety</strong>, and <strong>out-of-the-box best practices</strong>.</p>
</li>
</ul>
<p><strong>When to choose NestJS:</strong></p>
<p>NextJS is great for various use cases. It’s particularly effective if you’re building a large-scale API or microservice suite, if you want a solid architecture from day one, and if you prefer TypeScript and DI to keep code testable and maintainable.</p>
<p>With these advantages in mind, you’ll find that NestJS can dramatically speed up development, especially on projects that need robust structure and clear boundaries.</p>
<p>In the next section, we’ll dive into getting started: installing the CLI, creating a project, and exploring the generated folder layout.</p>
<h2 id="heading-3-getting-started">3. Getting Started</h2>
<p>Let’s jump into the basics: installing the CLI, scaffolding a new project, and exploring the default folder layout.</p>
<h3 id="heading-31-installing-the-cli">3.1 Installing the CLI</h3>
<p>Nest ships with an official command-line tool that helps you generate modules, controllers, services, and more. Under the hood it uses Yeoman templates to keep everything consistent.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Install the CLI globally (requires npm ≥ 6)</span>
npm install -g @nestjs/cli
</code></pre>
<p>Once installed, you can run <code>nest --help</code> to see available commands:</p>
<pre><code class="lang-bash">nest --<span class="hljs-built_in">help</span>
Usage: nest &lt;<span class="hljs-built_in">command</span>&gt; [options]

Commands:
  new &lt;name&gt;       Scaffold a new project
  generate|g &lt;schematic&gt; [options]  Generate artifacts (modules, controllers, ...)
  build            Build project with webpack
  ...

Options:
  -v, --version    Show version number
  -h, --<span class="hljs-built_in">help</span>       Show <span class="hljs-built_in">help</span>
</code></pre>
<h3 id="heading-32-creating-your-first-project">3.2 Creating Your First Project</h3>
<p>Scaffolding a new app is a single command. The CLI will ask whether to use npm or yarn, and whether to enable strict TypeScript settings.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Create a new Nest app in the "my-nest-app" folder</span>
nest new my-nest-app
</code></pre>
<p>After answering the prompts, you’ll have:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> my-nest-app
npm run start:dev
</code></pre>
<p>This launches a development server on <a target="_blank" href="http://localhost:3000"><code>http://localhost:3000</code></a> with automatic reload on file changes.</p>
<h3 id="heading-33-project-structure-overview">3.3 Project Structure Overview</h3>
<p>By default, you’ll see something like:</p>
<pre><code class="lang-bash">my-nest-app/
├── src/
│   ├── app.controller.ts      <span class="hljs-comment"># example controller</span>
│   ├── app.controller.spec.ts <span class="hljs-comment"># unit test for controller</span>
│   ├── app.module.ts          <span class="hljs-comment"># root application module</span>
│   ├── app.service.ts         <span class="hljs-comment"># example provider</span>
│   └── main.ts                <span class="hljs-comment"># entry point (bootstraps Nest)</span>
├── <span class="hljs-built_in">test</span>/                      <span class="hljs-comment"># end-to-end tests</span>
├── node_modules/
├── package.json
├── tsconfig.json
└── nest-cli.json             <span class="hljs-comment"># CLI configuration</span>
</code></pre>
<ul>
<li><p><strong>src/main.ts</strong><br>  The “bootstrap” script. It creates a Nest application instance and starts listening on a port:</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">import</span> { NestFactory } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/core'</span>;
  <span class="hljs-keyword">import</span> { AppModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.module'</span>;

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bootstrap</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> app = <span class="hljs-keyword">await</span> NestFactory.create(AppModule);
    <span class="hljs-keyword">await</span> app.listen(<span class="hljs-number">3000</span>);
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`🚀 Application is running on: <span class="hljs-subst">${<span class="hljs-keyword">await</span> app.getUrl()}</span>`</span>);
  }
  bootstrap();
</code></pre>
</li>
<li><p><strong>src/app.module.ts</strong><br>  The root module. It ties together controllers and providers:</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
  <span class="hljs-keyword">import</span> { AppController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.controller'</span>;
  <span class="hljs-keyword">import</span> { AppService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.service'</span>;

  <span class="hljs-meta">@Module</span>({
    imports: [],                 <span class="hljs-comment">// other modules to import</span>
    controllers: [AppController],
    providers: [AppService],
  })
  <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule {}
</code></pre>
</li>
<li><p><strong>src/app.controller.ts / app.service.ts</strong><br>  A simple example that shows dependency injection in action:</p>
<pre><code class="lang-typescript">  <span class="hljs-comment">// app.controller.ts</span>
  <span class="hljs-keyword">import</span> { Controller, Get } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
  <span class="hljs-keyword">import</span> { AppService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.service'</span>;

  <span class="hljs-meta">@Controller</span>()
  <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppController {
    <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> appService: AppService</span>) {}

    <span class="hljs-meta">@Get</span>()
    getHello(): <span class="hljs-built_in">string</span> {
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.appService.getHello();
    }
  }

  <span class="hljs-comment">// app.service.ts</span>
  <span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

  <span class="hljs-meta">@Injectable</span>()
  <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppService {
    getHello(): <span class="hljs-built_in">string</span> {
      <span class="hljs-keyword">return</span> <span class="hljs-string">'Hello, NestJS!'</span>;
    }
  }
</code></pre>
</li>
</ul>
<p>With this scaffold in place, you have a minimal – but fully functional – NestJS application. From here, you can generate new modules, controllers, and services:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Generate a new module, controller, and service for "tasks"</span>
nest g module tasks
nest g controller tasks
nest g service tasks
</code></pre>
<p>Each command will drop a new <code>.ts</code> file in the appropriate folder and update your module’s metadata. In the next section, we’ll dive into core Nest building blocks like modules, controllers, and providers in more detail.</p>
<h2 id="heading-4-core-nestjs-building-blocks">4. Core NestJS Building Blocks</h2>
<p>At the heart of every NestJS application are three pillars: <strong>Modules</strong>, <strong>Controllers</strong>, and <strong>Providers</strong> (often called Services). Let’s see what each one does, and how they fit together in theory and in practice.</p>
<h3 id="heading-41-modules">4.1 Modules</h3>
<p>A <strong>Module</strong> is a logical boundary – a container that groups related components (controllers, providers, and even other modules). Every NestJS app has at least one root module (usually <code>AppModule</code>), and you create feature modules (<code>UsersModule</code>, <code>AuthModule</code>, and so on) to organize code by domain.</p>
<h4 id="heading-module-decorator">@Module() Decorator</h4>
<ul>
<li><p><code>imports</code>: other modules to use</p>
</li>
<li><p><code>controllers</code>: controllers that handle incoming requests</p>
</li>
<li><p><code>providers</code>: services or values available via DI</p>
</li>
<li><p><code>exports</code>: providers that should be visible to importing modules</p>
</li>
</ul>
<p><strong>Here’s an example:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// cats.module.ts</span>
<span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { CatsController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./cats.controller'</span>;
<span class="hljs-keyword">import</span> { CatsService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./cats.service'</span>;

<span class="hljs-meta">@Module</span>({
  imports: [],            <span class="hljs-comment">// e.g. TypeOrmModule.forFeature([Cat])</span>
  controllers: [CatsController],
  providers: [CatsService],
  <span class="hljs-built_in">exports</span>: [CatsService], <span class="hljs-comment">// makes CatsService available to other modules</span>
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CatsModule {}
</code></pre>
<p>Then in your root module:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app.module.ts</span>
<span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { CatsModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./cats/cats.module'</span>;

<span class="hljs-meta">@Module</span>({
  imports: [CatsModule],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule {}
</code></pre>
<p>Now anything that injects <code>CatsService</code> will resolve to the one defined inside <code>CatsModule</code>.</p>
<h3 id="heading-42-controllers">4.2 Controllers</h3>
<p>A <strong>Controller</strong> maps incoming HTTP requests to handler methods. It’s responsible for extracting request data (query parameters, body, headers) and returning a response. Controllers should remain thin – delegating business logic to providers.</p>
<ul>
<li><p><strong>@Controller(path?)</strong>: Defines a route prefix</p>
</li>
<li><p><strong>@Get, @Post, @Put, @Delete, and so on</strong>: Define method-level routes</p>
</li>
<li><p><strong>@Param(), @Query(), @Body(), @Headers(), @Req(), @Res()</strong>: Decorators to extract request details</p>
</li>
</ul>
<p><strong>Here’s an example:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// cats.controller.ts</span>
<span class="hljs-keyword">import</span> { Controller, Get, Post, Body, Param } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { CatsService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./cats.service'</span>;
<span class="hljs-keyword">import</span> { CreateCatDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/create-cat.dto'</span>;

<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'cats'</span>)                  <span class="hljs-comment">// prefix: /cats</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CatsController {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> catsService: CatsService</span>) {}

  <span class="hljs-meta">@Get</span>()
  findAll() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.catsService.findAll();  <span class="hljs-comment">// GET /cats</span>
  }

  <span class="hljs-meta">@Get</span>(<span class="hljs-string">':id'</span>)
  findOne(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>) id: <span class="hljs-built_in">string</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.catsService.findOne(+id);  <span class="hljs-comment">// GET /cats/1</span>
  }

  <span class="hljs-meta">@Post</span>()
  create(<span class="hljs-meta">@Body</span>() createCatDto: CreateCatDto) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.catsService.create(createCatDto);  <span class="hljs-comment">// POST /cats</span>
  }
}
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// dto/create-cat.dto.ts</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CreateCatDto {
  <span class="hljs-keyword">readonly</span> name: <span class="hljs-built_in">string</span>;
  <span class="hljs-keyword">readonly</span> age: <span class="hljs-built_in">number</span>;
  <span class="hljs-keyword">readonly</span> breed?: <span class="hljs-built_in">string</span>;
}
</code></pre>
<h3 id="heading-43-providers-services">4.3 Providers (Services)</h3>
<p><strong>Providers</strong> are classes annotated with <code>@Injectable()</code> that contain your business logic or data access. Anything you want to inject elsewhere must be a provider. You can provide plain values, factory functions, or classes.</p>
<ul>
<li><p><strong>@Injectable()</strong>: Marks a class as available for DI</p>
</li>
<li><p><strong>Scope</strong>: Default is singleton, but you can change to request or transient</p>
</li>
<li><p><strong>Custom Providers</strong>: Use <code>useClass</code>, <code>useValue</code>, <code>useFactory</code>, or <code>useExisting</code> for more control</p>
</li>
</ul>
<p><strong>Here’s an example:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// cats.service.ts</span>
<span class="hljs-keyword">import</span> { Injectable, NotFoundException } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { CreateCatDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/create-cat.dto'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CatsService {
  <span class="hljs-keyword">private</span> cats = [];

  create(dto: CreateCatDto) {
    <span class="hljs-keyword">const</span> newCat = { id: <span class="hljs-built_in">Date</span>.now(), ...dto };
    <span class="hljs-built_in">this</span>.cats.push(newCat);
    <span class="hljs-keyword">return</span> newCat;
  }

  findAll() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.cats;
  }

  findOne(id: <span class="hljs-built_in">number</span>) {
    <span class="hljs-keyword">const</span> cat = <span class="hljs-built_in">this</span>.cats.find(<span class="hljs-function"><span class="hljs-params">c</span> =&gt;</span> c.id === id);
    <span class="hljs-keyword">if</span> (!cat) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotFoundException(<span class="hljs-string">`Cat #<span class="hljs-subst">${id}</span> not found`</span>);
    }
    <span class="hljs-keyword">return</span> cat;
  }
}
</code></pre>
<p><strong>Injecting a Custom Value:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// logger.provider.ts</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> LOGGER = {
  provide: <span class="hljs-string">'LOGGER'</span>,
  useValue: <span class="hljs-built_in">console</span>,
};

<span class="hljs-comment">// app.module.ts</span>
<span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { LOGGER } <span class="hljs-keyword">from</span> <span class="hljs-string">'./logger.provider'</span>;

<span class="hljs-meta">@Module</span>({
  providers: [LOGGER],
  <span class="hljs-built_in">exports</span>: [LOGGER],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule {}
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// some.service.ts</span>
<span class="hljs-keyword">import</span> { Inject, Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> SomeService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-meta">@Inject</span>(<span class="hljs-string">'LOGGER'</span>) <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> logger: Console</span>) {}

  logMessage(msg: <span class="hljs-built_in">string</span>) {
    <span class="hljs-built_in">this</span>.logger.log(<span class="hljs-string">`Custom log: <span class="hljs-subst">${msg}</span>`</span>);
  }
}
</code></pre>
<p>With modules wiring up controllers and providers, NestJS gives you a scalable, testable foundation. In the next section, we’ll explore <strong>Dependency Injection</strong> in depth – how it works under the hood and how to create custom providers and factory-based injections.</p>
<h2 id="heading-5-dependency-injection">5. Dependency Injection</h2>
<p>Nest’s built-in Dependency Injection (DI) system is the heart of how components (controllers, services, and so on) talk to each other in a loosely-coupled, testable way.</p>
<h3 id="heading-51-how-di-works-in-nestjs">5.1 How DI Works in NestJS</h3>
<p>When your application boots, Nest builds a <strong>module-based IoC container</strong>. Each <code>@Injectable()</code> provider is registered in the container under a token (by default, its class). When a class declares a dependency in its constructor, Nest looks up that token and injects the matching instance.</p>
<ul>
<li><p><strong>Singleton scope</strong>: One instance per application (default)</p>
</li>
<li><p><strong>Request scope</strong>: New instance per incoming request</p>
</li>
<li><p><strong>Transient scope</strong>: New instance every time it’s injected</p>
</li>
</ul>
<p><strong>Here’s an example:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// cats.service.ts</span>
<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CatsService {
  <span class="hljs-comment">// ...</span>
}

<span class="hljs-comment">// cats.controller.ts</span>
<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'cats'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CatsController {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> catsService: CatsService</span>) {}
  <span class="hljs-comment">// Nest sees CatsService in the constructor,</span>
  <span class="hljs-comment">// finds its singleton instance, and injects it.</span>
}
</code></pre>
<p><em>Behind the scenes</em>, Nest collects metadata from decorators (<code>@Injectable()</code>, <code>@Controller()</code>) and builds a graph of providers. When you call <code>NestFactory.create(AppModule)</code>, it resolves that graph and wires everything together.</p>
<h3 id="heading-52-custom-providers-and-factory-providers">5.2 Custom Providers and Factory Providers</h3>
<p>Sometimes you need to inject non-class values (APIs, constants) or run logic at registration time. Nest lets you define <strong>custom providers</strong> using the <code>provide</code> syntax.</p>
<h4 id="heading-usevalue"><code>useValue</code></h4>
<p>Inject a plain value or object:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// config.constant.ts</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> APP_NAME = {
  provide: <span class="hljs-string">'APP_NAME'</span>,
  useValue: <span class="hljs-string">'MyAwesomeApp'</span>,
};

<span class="hljs-comment">// app.module.ts</span>
<span class="hljs-meta">@Module</span>({
  providers: [APP_NAME],
  <span class="hljs-built_in">exports</span>: [<span class="hljs-string">'APP_NAME'</span>],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule {}

<span class="hljs-comment">// some.service.ts</span>
<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> SomeService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-meta">@Inject</span>(<span class="hljs-string">'APP_NAME'</span>) <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> name: <span class="hljs-built_in">string</span></span>) {}

  whoAmI() {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`Running in <span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span>`</span>;
  }
}
</code></pre>
<h4 id="heading-useclass"><code>useClass</code></h4>
<p>Swap implementations easily (useful for testing or feature flags):</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// logger.interface.ts</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Logger {
  log(msg: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">void</span>;
}

<span class="hljs-comment">// console-logger.ts</span>
<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ConsoleLogger <span class="hljs-keyword">implements</span> Logger {
  log(msg: <span class="hljs-built_in">string</span>) { <span class="hljs-built_in">console</span>.log(msg); }
}

<span class="hljs-comment">// file-logger.ts</span>
<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> FileLogger <span class="hljs-keyword">implements</span> Logger {
  log(msg: <span class="hljs-built_in">string</span>) { <span class="hljs-comment">/* write to file */</span> }
}

<span class="hljs-comment">// app.module.ts</span>
<span class="hljs-meta">@Module</span>({
  providers: [
    { provide: <span class="hljs-string">'Logger'</span>, useClass: FileLogger }, 
  ],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule {}

<span class="hljs-comment">// any.service.ts</span>
<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AnyService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-meta">@Inject</span>(<span class="hljs-string">'Logger'</span>) <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> logger: Logger</span>) {}
}
</code></pre>
<h4 id="heading-usefactory"><code>useFactory</code></h4>
<p>Run arbitrary factory logic (for example, async initialization, dynamic config):</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// database.provider.ts</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> DATABASE = {
  provide: <span class="hljs-string">'DATABASE'</span>,
  useFactory: <span class="hljs-keyword">async</span> (configService: ConfigService) =&gt; {
    <span class="hljs-keyword">const</span> opts = configService.getDbOptions();
    <span class="hljs-keyword">const</span> connection = <span class="hljs-keyword">await</span> createConnection(opts);
    <span class="hljs-keyword">return</span> connection;
  },
  inject: [ConfigService],
};

<span class="hljs-comment">// app.module.ts</span>
<span class="hljs-meta">@Module</span>({
  imports: [ConfigModule],
  providers: [DATABASE],
  <span class="hljs-built_in">exports</span>: [<span class="hljs-string">'DATABASE'</span>],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule {}

<span class="hljs-comment">// users.service.ts</span>
<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-meta">@Inject</span>(<span class="hljs-string">'DATABASE'</span>) <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> db: Connection</span>) {}
}
</code></pre>
<p>With custom providers and the factory pattern, you can integrate external libraries, toggle implementations, or perform async setup – all while retaining the clear, testable structure NestJS provides.</p>
<p>In the next section we’ll look at <strong>Routing and Middleware</strong>, showing how to define route handlers, apply global or per-route middleware, and extend your HTTP pipeline.</p>
<h2 id="heading-6-routing-amp-middleware">6. Routing &amp; Middleware</h2>
<p>Routing in NestJS is built on top of your controllers and decorators, while middleware lets you hook into the request/response pipeline for cross-cutting concerns like logging, authentication checks, or CORS.</p>
<h3 id="heading-61-defining-routes">6.1 Defining Routes</h3>
<p>First, a bit of theory:</p>
<ul>
<li><p><strong>@Controller(path?)</strong> sets a URL prefix for all routes in that class.</p>
</li>
<li><p><strong>@Get, @Post, @Put, @Delete, etc.</strong> define HTTP-method handlers.</p>
</li>
<li><p><strong>@Param(), @Query(), @Body(), @Headers(), @Req(), @Res()</strong> extract parts of the incoming request.</p>
</li>
</ul>
<p>You can combine route decorators and parameter decorators to build expressive, type-safe endpoints.</p>
<p><strong>Here’s an example:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// products.controller.ts</span>
<span class="hljs-keyword">import</span> { Controller, Get, Post, Param, Query, Body } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { ProductsService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./products.service'</span>;
<span class="hljs-keyword">import</span> { CreateProductDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/create-product.dto'</span>;

<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'products'</span>)                <span class="hljs-comment">// all routes here start with /products</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ProductsController {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> productsService: ProductsService</span>) {}

  <span class="hljs-meta">@Get</span>()                              <span class="hljs-comment">// GET /products</span>
  findAll(
    <span class="hljs-meta">@Query</span>(<span class="hljs-string">'limit'</span>) limit = <span class="hljs-string">'10'</span>,     <span class="hljs-comment">// optional query ?limit=20</span>
  ) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.productsService.findAll(+limit);
  }

  <span class="hljs-meta">@Get</span>(<span class="hljs-string">':id'</span>)                         <span class="hljs-comment">// GET /products/123</span>
  findOne(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>) id: <span class="hljs-built_in">string</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.productsService.findOne(+id);
  }

  <span class="hljs-meta">@Post</span>()                             <span class="hljs-comment">// POST /products</span>
  create(<span class="hljs-meta">@Body</span>() dto: CreateProductDto) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.productsService.create(dto);
  }
}
</code></pre>
<p>You can also nest controllers by importing a feature module, and use <strong>@Patch</strong>, <strong>@Put</strong>, <strong>@Delete</strong>, <strong>@Head</strong>, and so on for full RESTful coverage.</p>
<h3 id="heading-62-applying-middleware">6.2 Applying Middleware</h3>
<p><strong>Middleware</strong> are functions that run <em>before</em> your routes handle a request. They’re useful for logging, body-parsing (though Nest provides built-ins), authentication guards at a lower level, rate limiting, and so on.</p>
<p>You can implement them either as a functional middleware or a class implementing <code>NestMiddleware</code>.</p>
<p><strong>Here’s an example (Functional Middleware):</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// logger.middleware.ts</span>
<span class="hljs-keyword">import</span> { Request, Response, NextFunction } <span class="hljs-keyword">from</span> <span class="hljs-string">'express'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">logger</span>(<span class="hljs-params">req: Request, res: Response, next: NextFunction</span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`[<span class="hljs-subst">${<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toISOString()}</span>] <span class="hljs-subst">${req.method}</span> <span class="hljs-subst">${req.url}</span>`</span>);
  next();
}

<span class="hljs-comment">// app.module.ts</span>
<span class="hljs-keyword">import</span> { Module, NestModule, MiddlewareConsumer } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { logger } <span class="hljs-keyword">from</span> <span class="hljs-string">'./logger.middleware'</span>;
<span class="hljs-keyword">import</span> { ProductsModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./products/products.module'</span>;

<span class="hljs-meta">@Module</span>({
  imports: [ProductsModule],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule <span class="hljs-keyword">implements</span> NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(logger)                 <span class="hljs-comment">// apply logger</span>
      .forRoutes(<span class="hljs-string">'products'</span>);        <span class="hljs-comment">// only for /products routes</span>
  }
}
</code></pre>
<p><strong>And here’s another example (Class-based Middleware):</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// auth.middleware.ts</span>
<span class="hljs-keyword">import</span> { Injectable, NestMiddleware } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { Request, Response, NextFunction } <span class="hljs-keyword">from</span> <span class="hljs-string">'express'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AuthMiddleware <span class="hljs-keyword">implements</span> NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    <span class="hljs-keyword">if</span> (!req.headers.authorization) {
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">401</span>).send(<span class="hljs-string">'Unauthorized'</span>);
    }
    <span class="hljs-comment">// validate token...</span>
    next();
  }
}

<span class="hljs-comment">// security.module.ts</span>
<span class="hljs-keyword">import</span> { Module, NestModule, MiddlewareConsumer } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { AuthMiddleware } <span class="hljs-keyword">from</span> <span class="hljs-string">'./auth.middleware'</span>;
<span class="hljs-keyword">import</span> { UsersController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.controller'</span>;

<span class="hljs-meta">@Module</span>({
  controllers: [UsersController],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> SecurityModule <span class="hljs-keyword">implements</span> NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(AuthMiddleware)
      .forRoutes(UsersController);    <span class="hljs-comment">// apply to all routes in UsersController</span>
  }
}
</code></pre>
<p><strong>Tip:</strong> Global middleware can be applied in your <code>main.ts</code> before the <code>app.listen()</code> call via <code>app.use(logger)</code> if you want it on <em>every</em> request.</p>
<p>With routing and middleware set up, you have full control over how requests flow through your application. Next up, we’ll dive into <strong>Request Lifecycle and Pipes</strong>, exploring how data transforms and validations happen as part of each request.</p>
<h2 id="heading-7-request-lifecycle-amp-pipes">7. Request Lifecycle &amp; Pipes</h2>
<p>NestJS processes each incoming request through a defined “lifecycle” of steps – routing to the correct handler, applying <strong>pipes</strong>, <strong>guards</strong>, <strong>interceptors</strong>, and finally invoking your controller method. <strong>Pipes</strong> sit between the incoming request and your handler, transforming or validating data before it reaches your business logic.</p>
<h3 id="heading-71-what-are-pipes">7.1 What Are Pipes?</h3>
<p>A <strong>Pipe</strong> is a class annotated with <code>@Injectable()</code> that implements the <code>PipeTransform</code> interface. It has a single method:</p>
<pre><code class="lang-typescript">transform(value: <span class="hljs-built_in">any</span>, metadata: ArgumentMetadata): <span class="hljs-built_in">any</span>
</code></pre>
<ul>
<li><p><strong>Transformation</strong>: Convert input data (for example, a string <code>"123"</code>) into the desired type (<code>number</code> <code>123</code>).</p>
</li>
<li><p><strong>Validation</strong>: Check that incoming data meets certain rules and throw an exception (usually a <code>BadRequestException</code>) if it doesn’t.</p>
</li>
</ul>
<p>By default, pipes run <strong>after</strong> middleware and <strong>before</strong> guards/interceptors, for each decorated parameter (<code>@Body()</code>, <code>@Param()</code>, and so on).</p>
<p><strong>Here’s how it works:</strong><br>Nest ships with a handy global validation pipe that integrates with class-validator:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// main.ts</span>
<span class="hljs-keyword">import</span> { ValidationPipe } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { NestFactory }    <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/core'</span>;
<span class="hljs-keyword">import</span> { AppModule }      <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.module'</span>;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bootstrap</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> app = <span class="hljs-keyword">await</span> NestFactory.create(AppModule);
  <span class="hljs-comment">// Automatically validate and strip unknown properties</span>
  app.useGlobalPipes(<span class="hljs-keyword">new</span> ValidationPipe({ whitelist: <span class="hljs-literal">true</span>, forbidNonWhitelisted: <span class="hljs-literal">true</span> }));
  <span class="hljs-keyword">await</span> app.listen(<span class="hljs-number">3000</span>);
}
bootstrap();
</code></pre>
<p>With this in place, any DTO annotated with validation decorators will be checked before your handler runs:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// dto/create-user.dto.ts</span>
<span class="hljs-keyword">import</span> { IsEmail, IsString, MinLength } <span class="hljs-keyword">from</span> <span class="hljs-string">'class-validator'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CreateUserDto {
  <span class="hljs-meta">@IsEmail</span>()           <span class="hljs-comment">// must be a valid email</span>
  email: <span class="hljs-built_in">string</span>;

  <span class="hljs-meta">@IsString</span>()          <span class="hljs-comment">// must be a string</span>
  <span class="hljs-meta">@MinLength</span>(<span class="hljs-number">8</span>)        <span class="hljs-comment">// at least 8 characters</span>
  password: <span class="hljs-built_in">string</span>;
}

<span class="hljs-comment">// users.controller.ts</span>
<span class="hljs-meta">@Post</span>()
createUser(<span class="hljs-meta">@Body</span>() dto: CreateUserDto) {
  <span class="hljs-comment">// If body.email isn't an email, or password is shorter,</span>
  <span class="hljs-comment">// Nest throws a 400 Bad Request with details.</span>
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.usersService.create(dto);
}
</code></pre>
<h3 id="heading-72-built-in-vs-custom-pipes">7.2 Built-In vs. Custom Pipes</h3>
<h4 id="heading-built-in-pipes">Built-In Pipes</h4>
<p>Nest provides several out-of-the-box pipes:</p>
<ul>
<li><p><strong>ValidationPipe</strong>: Integrates with <code>class-validator</code> for DTO validation (shown above).</p>
</li>
<li><p><strong>ParseIntPipe</strong>: Converts a route parameter to <code>number</code> or throws <code>BadRequestException</code>.</p>
</li>
<li><p><strong>ParseBoolPipe</strong>, <strong>ParseUUIDPipe</strong>, <strong>ParseFloatPipe</strong>, and so on.</p>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-meta">@Get</span>(<span class="hljs-string">':id'</span>)
getById(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>, ParseIntPipe) id: <span class="hljs-built_in">number</span>) {
  <span class="hljs-comment">// id is guaranteed to be a number here</span>
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.itemsService.findOne(id);
}
</code></pre>
<h4 id="heading-custom-pipes">Custom Pipes</h4>
<p>You can write your own to handle any transformation or validation logic:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { PipeTransform, Injectable, BadRequestException } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ParsePositiveIntPipe <span class="hljs-keyword">implements</span> PipeTransform&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">number</span>&gt; {
  transform(value: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">number</span> {
    <span class="hljs-keyword">const</span> val = <span class="hljs-built_in">parseInt</span>(value, <span class="hljs-number">10</span>);
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">isNaN</span>(val) || val &lt;= <span class="hljs-number">0</span>) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> BadRequestException(<span class="hljs-string">`"<span class="hljs-subst">${value}</span>" is not a positive integer`</span>);
    }
    <span class="hljs-keyword">return</span> val;
  }
}
</code></pre>
<p>Use it just like a built-in pipe:</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@Get</span>(<span class="hljs-string">'order/:orderId'</span>)
getOrder(
  <span class="hljs-meta">@Param</span>(<span class="hljs-string">'orderId'</span>, ParsePositiveIntPipe) orderId: <span class="hljs-built_in">number</span>
) {
  <span class="hljs-comment">// orderId is a validated, positive integer</span>
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.ordersService.findById(orderId);
}
</code></pre>
<p>With pipes you ensure that every piece of data entering your handlers is correctly typed and valid, keeping your business logic clean and focused. In the next section, we’ll explore <strong>Guards and Authorization</strong> to control access to your endpoints.</p>
<h2 id="heading-8-guards-amp-authorization">8. Guards &amp; Authorization</h2>
<p>Guards sit in the request lifecycle <strong>after</strong> pipes and <strong>before</strong> interceptors/controllers. They determine whether a given request should be allowed to proceed based on custom logic. This is ideal for authentication, role checks, or feature flags.</p>
<h3 id="heading-81-implementing-guards">8.1 Implementing Guards</h3>
<p>A <strong>Guard</strong> is a class that implements the <code>CanActivate</code> interface, with a single method:</p>
<pre><code class="lang-typescript">canActivate(context: ExecutionContext): <span class="hljs-built_in">boolean</span> | <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">boolean</span>&gt; | Observable&lt;<span class="hljs-built_in">boolean</span>&gt;;
</code></pre>
<ul>
<li><p><strong>ExecutionContext</strong> gives you access to the underlying request/response and route metadata.</p>
</li>
<li><p>If <code>canActivate</code> returns <code>true</code>, the request continues. Returning <code>false</code> or throwing an exception (for example, <code>UnauthorizedException</code>) blocks it.</p>
</li>
</ul>
<p>You register guards either <strong>globally</strong>, at the <strong>controller</strong> level, or on <strong>individual routes</strong> with the <code>@UseGuards()</code> decorator.</p>
<p><strong>Here’s how guards work:</strong></p>
<ol>
<li><strong>Creating a simple auth guard:</strong></li>
</ol>
<pre><code class="lang-typescript"><span class="hljs-comment">// auth.guard.ts</span>
<span class="hljs-keyword">import</span> { Injectable, CanActivate, ExecutionContext, UnauthorizedException } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AuthGuard <span class="hljs-keyword">implements</span> CanActivate {
  canActivate(context: ExecutionContext): <span class="hljs-built_in">boolean</span> {
    <span class="hljs-keyword">const</span> req = context.switchToHttp().getRequest();
    <span class="hljs-keyword">const</span> authHeader = req.headers.authorization;
    <span class="hljs-keyword">if</span> (!authHeader || !authHeader.startsWith(<span class="hljs-string">'Bearer '</span>)) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnauthorizedException(<span class="hljs-string">'Missing or invalid authorization header'</span>);
    }
    <span class="hljs-comment">// Basic token check (replace with real validation)</span>
    <span class="hljs-keyword">const</span> token = authHeader.split(<span class="hljs-string">' '</span>)[<span class="hljs-number">1</span>];
    <span class="hljs-keyword">if</span> (token !== <span class="hljs-string">'valid-token'</span>) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnauthorizedException(<span class="hljs-string">'Invalid token'</span>);
    }
    <span class="hljs-comment">// Attach user info if needed:</span>
    req.user = { id: <span class="hljs-number">1</span>, name: <span class="hljs-string">'Alice'</span> };
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
  }
}
</code></pre>
<ol start="2">
<li><strong>Applying the guard</strong></li>
</ol>
<ul>
<li><p><strong>Globally</strong> (in <code>main.ts</code>):</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">import</span> { NestFactory } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/core'</span>;
  <span class="hljs-keyword">import</span> { AppModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.module'</span>;
  <span class="hljs-keyword">import</span> { AuthGuard } <span class="hljs-keyword">from</span> <span class="hljs-string">'./auth.guard'</span>;

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bootstrap</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> app = <span class="hljs-keyword">await</span> NestFactory.create(AppModule);
    <span class="hljs-comment">// every incoming request passes through AuthGuard</span>
    app.useGlobalGuards(<span class="hljs-keyword">new</span> AuthGuard());
    <span class="hljs-keyword">await</span> app.listen(<span class="hljs-number">3000</span>);
  }
  bootstrap();
</code></pre>
</li>
<li><p><strong>Controller-Level</strong>:</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">import</span> { Controller, Get, UseGuards } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
  <span class="hljs-keyword">import</span> { AuthGuard } <span class="hljs-keyword">from</span> <span class="hljs-string">'./auth.guard'</span>;

  <span class="hljs-meta">@Controller</span>(<span class="hljs-string">'profile'</span>)
  <span class="hljs-meta">@UseGuards</span>(AuthGuard)       <span class="hljs-comment">// applies to all routes in this controller</span>
  <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ProfileController {
    <span class="hljs-meta">@Get</span>()
    getProfile(<span class="hljs-meta">@Req</span>() req) {
      <span class="hljs-keyword">return</span> req.user;
    }
  }
</code></pre>
</li>
<li><p><strong>Route-Level</strong>:</p>
<pre><code class="lang-typescript">  <span class="hljs-meta">@Get</span>(<span class="hljs-string">'admin'</span>)
  <span class="hljs-meta">@UseGuards</span>(AdminGuard, AuthGuard)  <span class="hljs-comment">// chain multiple guards</span>
  getAdminData() { <span class="hljs-comment">/* ... */</span> }
</code></pre>
</li>
</ul>
<h3 id="heading-82-role-based-access-control">8.2 Role-Based Access Control</h3>
<p>Beyond plain authentication, you often need <strong>authorization</strong> – ensuring a user has the correct role or permission. You can build a guard that reads metadata (for example, required roles) and verifies user claims.</p>
<p><strong>Here’s how it works:</strong></p>
<ol>
<li><strong>Define a roles decorator:</strong></li>
</ol>
<pre><code class="lang-typescript"><span class="hljs-comment">// roles.decorator.ts</span>
<span class="hljs-keyword">import</span> { SetMetadata } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> Roles = <span class="hljs-function">(<span class="hljs-params">...roles: <span class="hljs-built_in">string</span>[]</span>) =&gt;</span> SetMetadata(<span class="hljs-string">'roles'</span>, roles);
</code></pre>
<ol start="2">
<li><strong>Create a roles guard:</strong></li>
</ol>
<pre><code class="lang-typescript"><span class="hljs-comment">// roles.guard.ts</span>
<span class="hljs-keyword">import</span> { Injectable, CanActivate, ExecutionContext, ForbiddenException } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { Reflector } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/core'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> RolesGuard <span class="hljs-keyword">implements</span> CanActivate {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> reflector: Reflector</span>) {}

  canActivate(context: ExecutionContext): <span class="hljs-built_in">boolean</span> {
    <span class="hljs-keyword">const</span> requiredRoles = <span class="hljs-built_in">this</span>.reflector.get&lt;<span class="hljs-built_in">string</span>[]&gt;(<span class="hljs-string">'roles'</span>, context.getHandler());
    <span class="hljs-keyword">if</span> (!requiredRoles) {
      <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>; <span class="hljs-comment">// no roles metadata =&gt; open route</span>
    }
    <span class="hljs-keyword">const</span> { user } = context.switchToHttp().getRequest();
    <span class="hljs-keyword">const</span> hasRole = requiredRoles.some(<span class="hljs-function"><span class="hljs-params">role</span> =&gt;</span> user.roles?.includes(role));
    <span class="hljs-keyword">if</span> (!hasRole) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ForbiddenException(<span class="hljs-string">'You do not have permission (roles)'</span>);
    }
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
  }
}
</code></pre>
<ol start="3">
<li><strong>Apply roles metadata and guard:</strong></li>
</ol>
<pre><code class="lang-typescript"><span class="hljs-meta">@Controller</span>(<span class="hljs-string">'projects'</span>)
<span class="hljs-meta">@UseGuards</span>(AuthGuard, RolesGuard)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ProjectsController {
  <span class="hljs-meta">@Get</span>()
  <span class="hljs-meta">@Roles</span>(<span class="hljs-string">'user'</span>, <span class="hljs-string">'admin'</span>)         <span class="hljs-comment">// route requires either 'user' or 'admin'</span>
  findAll() { <span class="hljs-comment">/* ... */</span> }

  <span class="hljs-meta">@Post</span>()
  <span class="hljs-meta">@Roles</span>(<span class="hljs-string">'admin'</span>)                 <span class="hljs-comment">// only 'admin' can create</span>
  create() { <span class="hljs-comment">/* ... */</span> }
}
</code></pre>
<p>With this setup:</p>
<ul>
<li><p><code>AuthGuard</code> ensures the request is authenticated and populates <code>req.user</code>.</p>
</li>
<li><p><code>RolesGuard</code> reads the <code>@Roles()</code> metadata to enforce role-based access.</p>
</li>
</ul>
<p>Guards give you a powerful, declarative way to enforce security and authorization policies. In the next section, we’ll cover <strong>Exception Filters</strong> – how to catch and format errors centrally, keeping your controllers clean.</p>
<h2 id="heading-9-exception-filters">9. Exception Filters</h2>
<p>Exception filters let you centralize error handling, transforming thrown exceptions into consistent HTTP responses or other formats. You can rely on Nest’s built-in behavior for many cases, but custom filters give you control over logging, response shape, or handling non-HTTP errors.</p>
<h3 id="heading-91-handling-errors-gracefully">9.1 Handling Errors Gracefully</h3>
<p>By default, if a controller or service throws an <code>HttpException</code> (or one of Nest’s built-in exceptions like <code>NotFoundException</code>, <code>BadRequestException</code>, and so on), Nest catches it and sends an appropriate HTTP response with status code and JSON body containing <code>statusCode</code>, <code>message</code>, and <code>error</code>.</p>
<p>If an unexpected error (for example, a runtime error) bubbles up, Nest uses its default exception filter to return a 500 Internal Server Error with a generic message.</p>
<p>Controllers/services should throw exceptions rather than return error codes manually, so the framework can format consistently.</p>
<p><strong>Here’s how it works:</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// users.service.ts</span>
<span class="hljs-keyword">import</span> { Injectable, NotFoundException } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersService {
  <span class="hljs-keyword">private</span> users = [{ id: <span class="hljs-number">1</span>, name: <span class="hljs-string">'Alice'</span> }];

  findOne(id: <span class="hljs-built_in">number</span>) {
    <span class="hljs-keyword">const</span> user = <span class="hljs-built_in">this</span>.users.find(<span class="hljs-function"><span class="hljs-params">u</span> =&gt;</span> u.id === id);
    <span class="hljs-keyword">if</span> (!user) {
      <span class="hljs-comment">// results in 404 with JSON { statusCode: 404, message: 'User #2 not found', error: 'Not Found' }</span>
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotFoundException(<span class="hljs-string">`User #<span class="hljs-subst">${id}</span> not found`</span>);
    }
    <span class="hljs-keyword">return</span> user;
  }
}
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// users.controller.ts</span>
<span class="hljs-keyword">import</span> { Controller, Get, Param, ParseIntPipe } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'users'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersController {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> usersService: UsersService</span>) {}

  <span class="hljs-meta">@Get</span>(<span class="hljs-string">':id'</span>)
  getUser(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>, ParseIntPipe) id: <span class="hljs-built_in">number</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.usersService.findOne(id);
  }
}
</code></pre>
<p>If <code>findOne</code> throws, Nest’s default filter sends a structured JSON error. For unexpected errors (like a thrown <code>Error</code>), Nest wraps it into a 500 response.</p>
<h3 id="heading-92-creating-custom-filters">9.2 Creating Custom Filters</h3>
<p>You can implement the <code>ExceptionFilter</code> interface or extend <code>BaseExceptionFilter</code>. Just use the <code>@Catch()</code> decorator to target specific exception types (or leave empty to catch all).</p>
<p>In <code>catch(exception, host)</code>, you can extract context (HTTP request/response) and shape your response (for example, add metadata, custom fields, or a uniform envelope). You can also log exceptions or report to external systems here.</p>
<p>You can apply filters <strong>globally</strong>, to a controller, or to an individual route.</p>
<p><strong>Here’s how it works:</strong></p>
<ol>
<li><p><strong>Simple logging filter</strong><br> Catch all exceptions, log details, then delegate to default behavior:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// logging-exception.filter.ts</span>
 <span class="hljs-keyword">import</span> {
   ExceptionFilter,
   Catch,
   ArgumentsHost,
   HttpException,
   HttpStatus,
   Logger,
 } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { BaseExceptionFilter } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/core'</span>;

 <span class="hljs-meta">@Catch</span>() <span class="hljs-comment">// no args = catch every exception</span>
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> LoggingExceptionFilter <span class="hljs-keyword">extends</span> BaseExceptionFilter {
   <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> logger = <span class="hljs-keyword">new</span> Logger(LoggingExceptionFilter.name);

   <span class="hljs-keyword">catch</span>(exception: unknown, host: ArgumentsHost) {
     <span class="hljs-keyword">const</span> ctx = host.switchToHttp();
     <span class="hljs-keyword">const</span> req = ctx.getRequest&lt;Request&gt;();
     <span class="hljs-keyword">const</span> res = ctx.getResponse();

     <span class="hljs-comment">// Log stack or message</span>
     <span class="hljs-keyword">if</span> (exception <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Error</span>) {
       <span class="hljs-built_in">this</span>.logger.error(<span class="hljs-string">`Error on <span class="hljs-subst">${req.method}</span> <span class="hljs-subst">${req.url}</span>`</span>, exception.stack);
     } <span class="hljs-keyword">else</span> {
       <span class="hljs-built_in">this</span>.logger.error(<span class="hljs-string">`Unknown exception on <span class="hljs-subst">${req.method}</span> <span class="hljs-subst">${req.url}</span>`</span>);
     }

     <span class="hljs-comment">// Delegate to default filter for HTTP exceptions or generic 500</span>
     <span class="hljs-built_in">super</span>.catch(exception, host);
   }
 }
</code></pre>
<p> <strong>Apply globally</strong> in <code>main.ts</code>:</p>
<pre><code class="lang-typescript"> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bootstrap</span>(<span class="hljs-params"></span>) </span>{
   <span class="hljs-keyword">const</span> app = <span class="hljs-keyword">await</span> NestFactory.create(AppModule);
   app.useGlobalFilters(<span class="hljs-keyword">new</span> LoggingExceptionFilter(app.get(HttpAdapterHost)));
   <span class="hljs-keyword">await</span> app.listen(<span class="hljs-number">3000</span>);
 }
</code></pre>
<p> (If extending <code>BaseExceptionFilter</code>, pass the adapter host to the constructor or super as needed.)</p>
</li>
<li><p><strong>Custom response shape</strong><br> Suppose you want all errors to return <code>{ success: false, error: { code, message } }</code>:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// custom-response.filter.ts</span>
 <span class="hljs-keyword">import</span> {
   ExceptionFilter,
   Catch,
   ArgumentsHost,
   HttpException,
   HttpStatus,
 } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

 <span class="hljs-meta">@Catch</span>()
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CustomResponseFilter <span class="hljs-keyword">implements</span> ExceptionFilter {
   <span class="hljs-keyword">catch</span>(exception: unknown, host: ArgumentsHost) {
     <span class="hljs-keyword">const</span> ctx = host.switchToHttp();
     <span class="hljs-keyword">const</span> response = ctx.getResponse();
     <span class="hljs-keyword">const</span> request = ctx.getRequest&lt;Request&gt;();

     <span class="hljs-keyword">let</span> status: <span class="hljs-built_in">number</span>;
     <span class="hljs-keyword">let</span> message: <span class="hljs-built_in">string</span> | <span class="hljs-built_in">object</span>;

     <span class="hljs-keyword">if</span> (exception <span class="hljs-keyword">instanceof</span> HttpException) {
       status = exception.getStatus();
       <span class="hljs-keyword">const</span> res = exception.getResponse();
       <span class="hljs-comment">// res might be a string or object</span>
       message = <span class="hljs-keyword">typeof</span> res === <span class="hljs-string">'string'</span> ? { message: res } : res;
     } <span class="hljs-keyword">else</span> {
       status = HttpStatus.INTERNAL_SERVER_ERROR;
       message = { message: <span class="hljs-string">'Internal server error'</span> };
     }

     response.status(status).json({
       success: <span class="hljs-literal">false</span>,
       error: {
         statusCode: status,
         ...(
           <span class="hljs-keyword">typeof</span> message === <span class="hljs-string">'object'</span>
             ? message
             : { message }
         ),
       },
       timestamp: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toISOString(),
       path: request.url,
     });
   }
 }
</code></pre>
<p> <strong>Apply at controller or route level</strong>:</p>
<pre><code class="lang-typescript"> <span class="hljs-meta">@Controller</span>(<span class="hljs-string">'orders'</span>)
 <span class="hljs-meta">@UseFilters</span>(CustomResponseFilter)
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> OrdersController {
   <span class="hljs-comment">// ...</span>
 }
</code></pre>
</li>
<li><p><strong>Catching specific exceptions</strong><br> If you have a custom exception class:</p>
<pre><code class="lang-typescript"> <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> PaymentFailedException <span class="hljs-keyword">extends</span> HttpException {
   <span class="hljs-keyword">constructor</span>(<span class="hljs-params">details: <span class="hljs-built_in">string</span></span>) {
     <span class="hljs-built_in">super</span>({ message: <span class="hljs-string">'Payment failed'</span>, details }, HttpStatus.PAYMENT_REQUIRED);
   }
 }
</code></pre>
<p> You can write a filter that only catches that:</p>
<pre><code class="lang-typescript"> <span class="hljs-meta">@Catch</span>(PaymentFailedException)
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> PaymentFailedFilter <span class="hljs-keyword">implements</span> ExceptionFilter {
   <span class="hljs-keyword">catch</span>(exception: PaymentFailedException, host: ArgumentsHost) {
     <span class="hljs-keyword">const</span> ctx = host.switchToHttp();
     <span class="hljs-keyword">const</span> res = ctx.getResponse();
     <span class="hljs-keyword">const</span> status = exception.getStatus();
     <span class="hljs-keyword">const</span> { message, details } = exception.getResponse() <span class="hljs-keyword">as</span> <span class="hljs-built_in">any</span>;
     res.status(status).json({
       error: {
         message,
         details,
       },
       help: <span class="hljs-string">'Please verify your payment method and retry.'</span>,
     });
   }
 }
</code></pre>
<p> Then apply only where payments occur:</p>
<pre><code class="lang-typescript"> <span class="hljs-meta">@Post</span>(<span class="hljs-string">'charge'</span>)
 <span class="hljs-meta">@UseFilters</span>(PaymentFailedFilter)
 charge() {
   <span class="hljs-comment">// ...</span>
 }
</code></pre>
</li>
</ol>
<p>With exception filters in place, you ensure a consistent error contract, centralized logging or reporting, and tailored handling of different error types. Next up: <strong>Interceptors and Logging</strong>, where we’ll see how to transform responses, measure performance, and hook around method execution.</p>
<h2 id="heading-10-interceptors-amp-logging">10. Interceptors &amp; Logging</h2>
<p>Interceptors wrap around method execution, letting you transform responses, bind extra logic before/after method calls, or measure performance. They’re ideal for cross-cutting concerns like logging, response shaping, caching, or timing metrics.</p>
<h3 id="heading-101-transforming-responses">10.1 Transforming Responses</h3>
<p>An <strong>Interceptor</strong> implements the <code>NestInterceptor</code> interface with an <code>intercept(context, next)</code> method.</p>
<p>Inside <code>intercept</code>, you typically call <code>next.handle()</code> which returns an <code>Observable</code> of the handler’s result. You can then apply RxJS operators (like <code>map</code>) to modify the data before it’s sent to the client.</p>
<p>Common uses are wrapping all responses in a uniform envelope, filtering out certain fields, or adding metadata.</p>
<p><strong>Here’s how it works:</strong></p>
<ol>
<li><p><strong>Basic response wrapper</strong><br> Suppose you want every successful response to be <code>{ success: true, data: &lt;original&gt; }</code>.</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// response.interceptor.ts</span>
 <span class="hljs-keyword">import</span> {
   Injectable,
   NestInterceptor,
   ExecutionContext,
   CallHandler,
 } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { Observable } <span class="hljs-keyword">from</span> <span class="hljs-string">'rxjs'</span>;
 <span class="hljs-keyword">import</span> { map } <span class="hljs-keyword">from</span> <span class="hljs-string">'rxjs/operators'</span>;

 <span class="hljs-meta">@Injectable</span>()
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ResponseInterceptor <span class="hljs-keyword">implements</span> NestInterceptor {
   intercept(context: ExecutionContext, next: CallHandler): Observable&lt;<span class="hljs-built_in">any</span>&gt; {
     <span class="hljs-keyword">return</span> next.handle().pipe(
       map(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> ({
         success: <span class="hljs-literal">true</span>,
         data,
       })),
     );
   }
 }
</code></pre>
<p> <strong>Apply globally</strong> in <code>main.ts</code>:</p>
<pre><code class="lang-typescript"> <span class="hljs-keyword">import</span> { NestFactory } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/core'</span>;
 <span class="hljs-keyword">import</span> { AppModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.module'</span>;
 <span class="hljs-keyword">import</span> { ResponseInterceptor } <span class="hljs-keyword">from</span> <span class="hljs-string">'./common/response.interceptor'</span>;

 <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bootstrap</span>(<span class="hljs-params"></span>) </span>{
   <span class="hljs-keyword">const</span> app = <span class="hljs-keyword">await</span> NestFactory.create(AppModule);
   app.useGlobalInterceptors(<span class="hljs-keyword">new</span> ResponseInterceptor());
   <span class="hljs-keyword">await</span> app.listen(<span class="hljs-number">3000</span>);
 }
 bootstrap();
</code></pre>
<p> Now, if a controller method returns <code>{ id: 1, name: 'Alice' }</code>, the client sees:</p>
<pre><code class="lang-json"> {
   <span class="hljs-attr">"success"</span>: <span class="hljs-literal">true</span>,
   <span class="hljs-attr">"data"</span>: { <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Alice"</span> }
 }
</code></pre>
</li>
<li><p><strong>Filtering sensitive fields</strong><br> You might want to strip out fields like <code>password</code> before sending a user object:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// sanitize.interceptor.ts</span>
 <span class="hljs-keyword">import</span> {
   Injectable,
   NestInterceptor,
   ExecutionContext,
   CallHandler,
 } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { Observable } <span class="hljs-keyword">from</span> <span class="hljs-string">'rxjs'</span>;
 <span class="hljs-keyword">import</span> { map } <span class="hljs-keyword">from</span> <span class="hljs-string">'rxjs/operators'</span>;

 <span class="hljs-meta">@Injectable</span>()
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> SanitizeInterceptor <span class="hljs-keyword">implements</span> NestInterceptor {
   intercept(context: ExecutionContext, next: CallHandler): Observable&lt;<span class="hljs-built_in">any</span>&gt; {
     <span class="hljs-keyword">return</span> next.handle().pipe(
       map(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
         <span class="hljs-keyword">if</span> (data &amp;&amp; <span class="hljs-keyword">typeof</span> data === <span class="hljs-string">'object'</span>) {
           <span class="hljs-keyword">const</span> { password, ...rest } = data;
           <span class="hljs-keyword">return</span> rest;
         }
         <span class="hljs-keyword">return</span> data;
       }),
     );
   }
 }
</code></pre>
<p> <strong>Apply at controller or route</strong>:</p>
<pre><code class="lang-typescript"> <span class="hljs-meta">@Controller</span>(<span class="hljs-string">'users'</span>)
 <span class="hljs-meta">@UseInterceptors</span>(SanitizeInterceptor)
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersController {
   <span class="hljs-meta">@Get</span>(<span class="hljs-string">':id'</span>)
   getUser(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>) id: <span class="hljs-built_in">string</span>) {
     <span class="hljs-comment">// returns a user object with a password field internally,</span>
     <span class="hljs-comment">// but interceptor strips it before sending to client</span>
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.usersService.findOne(+id);
   }
 }
</code></pre>
</li>
<li><p><strong>Serializing with</strong> <code>class-transformer</code><br> If you use classes with decorators, you can integrate with <code>class-transformer</code>:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// user.entity.ts</span>
 <span class="hljs-keyword">import</span> { Exclude, Expose } <span class="hljs-keyword">from</span> <span class="hljs-string">'class-transformer'</span>;

 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> User {
   id: <span class="hljs-built_in">number</span>;
   name: <span class="hljs-built_in">string</span>;

   <span class="hljs-meta">@Exclude</span>()
   password: <span class="hljs-built_in">string</span>;

   <span class="hljs-meta">@Expose</span>()
   get displayName(): <span class="hljs-built_in">string</span> {
     <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span> (#<span class="hljs-subst">${<span class="hljs-built_in">this</span>.id}</span>)`</span>;
   }
 }
</code></pre>
<pre><code class="lang-typescript"> <span class="hljs-comment">// class-transform.interceptor.ts</span>
 <span class="hljs-keyword">import</span> {
   Injectable,
   NestInterceptor,
   ExecutionContext,
   CallHandler,
 } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { plainToInstance } <span class="hljs-keyword">from</span> <span class="hljs-string">'class-transformer'</span>;
 <span class="hljs-keyword">import</span> { Observable } <span class="hljs-keyword">from</span> <span class="hljs-string">'rxjs'</span>;
 <span class="hljs-keyword">import</span> { map } <span class="hljs-keyword">from</span> <span class="hljs-string">'rxjs/operators'</span>;

 <span class="hljs-meta">@Injectable</span>()
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ClassTransformInterceptor&lt;T&gt; <span class="hljs-keyword">implements</span> NestInterceptor {
   <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> dto: <span class="hljs-keyword">new</span> (...args: <span class="hljs-built_in">any</span>[]) =&gt; T</span>) {}

   intercept(context: ExecutionContext, next: CallHandler): Observable&lt;<span class="hljs-built_in">any</span>&gt; {
     <span class="hljs-keyword">return</span> next.handle().pipe(
       map(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
         <span class="hljs-keyword">return</span> plainToInstance(<span class="hljs-built_in">this</span>.dto, data, {
           excludeExtraneousValues: <span class="hljs-literal">true</span>,
         });
       }),
     );
   }
 }
</code></pre>
<p> <strong>Apply with a DTO</strong>:</p>
<pre><code class="lang-typescript"> <span class="hljs-meta">@Controller</span>(<span class="hljs-string">'users'</span>)
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersController {
   <span class="hljs-meta">@Get</span>(<span class="hljs-string">':id'</span>)
   <span class="hljs-meta">@UseInterceptors</span>(<span class="hljs-keyword">new</span> ClassTransformInterceptor(User))
   getUser(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>) id: <span class="hljs-built_in">string</span>) {
     <span class="hljs-comment">// service returns a plain object; interceptor transforms to User instance</span>
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.usersService.findOne(+id);
   }
 }
</code></pre>
</li>
</ol>
<h3 id="heading-102-logging-and-performance-metrics">10.2 Logging and Performance Metrics</h3>
<p>Interceptors can also measure execution time or log request/response details. You capture timestamps before and after <code>next.handle()</code>, logging the difference. This helps monitor slow endpoints. Combined with a logging framework or Nest’s <code>Logger</code>, you can standardize logs.</p>
<p><strong>Here’s how it works:</strong></p>
<ol>
<li><p><strong>Timing interceptor</strong><br> Logs how long each request-handler takes:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// logging.interceptor.ts</span>
 <span class="hljs-keyword">import</span> {
   Injectable,
   NestInterceptor,
   ExecutionContext,
   CallHandler,
   Logger,
 } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { Observable } <span class="hljs-keyword">from</span> <span class="hljs-string">'rxjs'</span>;
 <span class="hljs-keyword">import</span> { tap } <span class="hljs-keyword">from</span> <span class="hljs-string">'rxjs/operators'</span>;

 <span class="hljs-meta">@Injectable</span>()
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> LoggingInterceptor <span class="hljs-keyword">implements</span> NestInterceptor {
   <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> logger = <span class="hljs-keyword">new</span> Logger(LoggingInterceptor.name);

   intercept(context: ExecutionContext, next: CallHandler): Observable&lt;<span class="hljs-built_in">any</span>&gt; {
     <span class="hljs-keyword">const</span> req = context.switchToHttp().getRequest();
     <span class="hljs-keyword">const</span> method = req.method;
     <span class="hljs-keyword">const</span> url = req.url;
     <span class="hljs-keyword">const</span> now = <span class="hljs-built_in">Date</span>.now();
     <span class="hljs-keyword">return</span> next.handle().pipe(
       tap(<span class="hljs-function">() =&gt;</span> {
         <span class="hljs-keyword">const</span> elapsed = <span class="hljs-built_in">Date</span>.now() - now;
         <span class="hljs-built_in">this</span>.logger.log(<span class="hljs-string">`<span class="hljs-subst">${method}</span> <span class="hljs-subst">${url}</span> - <span class="hljs-subst">${elapsed}</span>ms`</span>);
       }),
     );
   }
 }
</code></pre>
<p> <strong>Apply globally</strong>:</p>
<pre><code class="lang-typescript"> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bootstrap</span>(<span class="hljs-params"></span>) </span>{
   <span class="hljs-keyword">const</span> app = <span class="hljs-keyword">await</span> NestFactory.create(AppModule);
   app.useGlobalInterceptors(<span class="hljs-keyword">new</span> LoggingInterceptor());
   <span class="hljs-keyword">await</span> app.listen(<span class="hljs-number">3000</span>);
 }
</code></pre>
<p> Now each request logs something like:</p>
<pre><code class="lang-bash"> [LoggingInterceptor] GET /users/1 - 35ms
</code></pre>
</li>
<li><p><strong>Detailed request/response logging</strong><br> For more detail, log request body or response size (careful with sensitive data):</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// detailed-logging.interceptor.ts</span>
 <span class="hljs-keyword">import</span> {
   Injectable,
   NestInterceptor,
   ExecutionContext,
   CallHandler,
   Logger,
 } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { Observable } <span class="hljs-keyword">from</span> <span class="hljs-string">'rxjs'</span>;
 <span class="hljs-keyword">import</span> { tap, map } <span class="hljs-keyword">from</span> <span class="hljs-string">'rxjs/operators'</span>;

 <span class="hljs-meta">@Injectable</span>()
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> DetailedLoggingInterceptor <span class="hljs-keyword">implements</span> NestInterceptor {
   <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> logger = <span class="hljs-keyword">new</span> Logger(<span class="hljs-string">'HTTP'</span>);

   intercept(context: ExecutionContext, next: CallHandler): Observable&lt;<span class="hljs-built_in">any</span>&gt; {
     <span class="hljs-keyword">const</span> ctx = context.switchToHttp();
     <span class="hljs-keyword">const</span> req = ctx.getRequest&lt;Request&gt;();
     <span class="hljs-keyword">const</span> { method, url, body } = req;
     <span class="hljs-keyword">const</span> now = <span class="hljs-built_in">Date</span>.now();

     <span class="hljs-built_in">this</span>.logger.log(<span class="hljs-string">`Incoming <span class="hljs-subst">${method}</span> <span class="hljs-subst">${url}</span> - body: <span class="hljs-subst">${<span class="hljs-built_in">JSON</span>.stringify(body)}</span>`</span>);

     <span class="hljs-keyword">return</span> next.handle().pipe(
       map(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
         <span class="hljs-keyword">const</span> elapsed = <span class="hljs-built_in">Date</span>.now() - now;
         <span class="hljs-built_in">this</span>.logger.log(<span class="hljs-string">`Response <span class="hljs-subst">${method}</span> <span class="hljs-subst">${url}</span> - <span class="hljs-subst">${elapsed}</span>ms - data: <span class="hljs-subst">${<span class="hljs-built_in">JSON</span>.stringify(data)}</span>`</span>);
         <span class="hljs-keyword">return</span> data;
       }),
     );
   }
 }
</code></pre>
<p> <strong>Apply conditionally</strong>: perhaps only in development:</p>
<pre><code class="lang-typescript"> <span class="hljs-keyword">if</span> (process.env.NODE_ENV !== <span class="hljs-string">'production'</span>) {
   app.useGlobalInterceptors(<span class="hljs-keyword">new</span> DetailedLoggingInterceptor());
 }
</code></pre>
</li>
<li><p><strong>Combining with guards/pipes</strong><br> Since interceptors run after guards and before the response is sent, logging time captures the full handler including service calls, but after validation/authorization. That ensures you measure only authorized requests and valid data flows.</p>
</li>
</ol>
<p>Interceptors offer a flexible way to wrap your handlers with extra behavior: transforming outputs, sanitizing data, timing execution, or adding headers. In the next section, we’ll explore <strong>Database integration</strong> to see how you can integrate your data layer in Nest.</p>
<h2 id="heading-11-database-integration">11. Database Integration</h2>
<p>In many real-world applications, persisting data is essential. NestJS offers first-class support and integrations for several database technologies. In this section we cover three common approaches:</p>
<ul>
<li><p><strong>TypeORM with NestJS</strong> (relational databases, Active Record/Data Mapper style)</p>
</li>
<li><p><strong>Mongoose (MongoDB)</strong> (NoSQL document store)</p>
</li>
<li><p><strong>Prisma</strong> (Type-safe query builder/ORM alternative)</p>
</li>
</ul>
<p>For each, we’ll explain the theory – when and why to choose it – and show concise practical examples of setup and usage in a NestJS context.</p>
<h3 id="heading-111-typeorm-with-nestjs">11.1 TypeORM with NestJS</h3>
<p>TypeORM is a popular ORM for Node.js that supports multiple relational databases (PostgreSQL, MySQL, SQLite, SQL Server, and so on), offering both Active Record and Data Mapper patterns.</p>
<p>In NestJS, the <code>@nestjs/typeorm</code> package wraps TypeORM to provide:</p>
<ul>
<li><p><strong>Automatic connection management</strong> via <code>TypeOrmModule.forRoot()</code></p>
</li>
<li><p><strong>Module-scoped repositories/entities</strong> via <code>TypeOrmModule.forFeature()</code></p>
</li>
<li><p><strong>Dependency injection</strong> for repositories and the <code>DataSource</code>/<code>Connection</code></p>
</li>
<li><p><strong>Entity decorators</strong> (<code>@Entity()</code>, <code>@Column()</code>, and so on) for schema definition</p>
</li>
<li><p><strong>Migrations</strong> and advanced features via TypeORM CLI or programmatic usage</p>
</li>
</ul>
<h4 id="heading-when-to-choose-typeorm">When to choose TypeORM</h4>
<p>Type ORM is useful in several scenarios. Use it when your data is relational and you want a full-featured ORM with decorators and built-in migrations. It’s also great if you prefer to work with classes/entities and automatically map them to tables. And it’s a great choice if you value built-in features like eager/lazy relations, cascading, query builders, and repository patterns.</p>
<h4 id="heading-heres-how-to-use-it">Here’s how to use it:</h4>
<ol>
<li><p><strong>Install dependencies:</strong></p>
<pre><code class="lang-bash"> npm install --save @nestjs/typeorm typeorm reflect-metadata
 <span class="hljs-comment"># Also install the database driver; e.g., for Postgres:</span>
 npm install --save pg
</code></pre>
</li>
<li><p><strong>Configure the root module:</strong></p>
<p> In <code>app.module.ts</code>, import <code>TypeOrmModule.forRoot()</code> with connection options. These can come from environment variables (discussed later in Configuration Management).</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/app.module.ts</span>
 <span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { TypeOrmModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/typeorm'</span>;
 <span class="hljs-keyword">import</span> { UsersModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users/users.module'</span>;

 <span class="hljs-meta">@Module</span>({
   imports: [
     TypeOrmModule.forRoot({
       <span class="hljs-keyword">type</span>: <span class="hljs-string">'postgres'</span>,
       host: process.env.DB_HOST || <span class="hljs-string">'localhost'</span>,
       port: +process.env.DB_PORT || <span class="hljs-number">5432</span>,
       username: process.env.DB_USER || <span class="hljs-string">'postgres'</span>,
       password: process.env.DB_PASS || <span class="hljs-string">'password'</span>,
       database: process.env.DB_NAME || <span class="hljs-string">'mydb'</span>,
       entities: [__dirname + <span class="hljs-string">'/**/*.entity{.ts,.js}'</span>],
       synchronize: <span class="hljs-literal">false</span>, <span class="hljs-comment">// recommended false in production; use migrations</span>
       <span class="hljs-comment">// logging: true,</span>
     }),
     UsersModule,
     <span class="hljs-comment">// ...other modules</span>
   ],
 })
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule {}
</code></pre>
<ul>
<li><p><code>synchronize: true</code> can auto-sync schema in development, but in production prefer migrations.</p>
</li>
<li><p>Entities are auto-loaded via glob. Ensure path matches compiled output.</p>
</li>
</ul>
</li>
<li><p><strong>Define an entity:</strong></p>
<p> Create an entity class with decorators:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/users/user.entity.ts</span>
 <span class="hljs-keyword">import</span> { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } <span class="hljs-keyword">from</span> <span class="hljs-string">'typeorm'</span>;

 <span class="hljs-meta">@Entity</span>({ name: <span class="hljs-string">'users'</span> })
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> User {
   <span class="hljs-meta">@PrimaryGeneratedColumn</span>()
   id: <span class="hljs-built_in">number</span>;

   <span class="hljs-meta">@Column</span>({ unique: <span class="hljs-literal">true</span> })
   email: <span class="hljs-built_in">string</span>;

   <span class="hljs-meta">@Column</span>()
   password: <span class="hljs-built_in">string</span>;

   <span class="hljs-meta">@Column</span>({ nullable: <span class="hljs-literal">true</span> })
   name?: <span class="hljs-built_in">string</span>;

   <span class="hljs-meta">@CreateDateColumn</span>()
   createdAt: <span class="hljs-built_in">Date</span>;

   <span class="hljs-meta">@UpdateDateColumn</span>()
   updatedAt: <span class="hljs-built_in">Date</span>;
 }
</code></pre>
</li>
<li><p><strong>Set up the feature module:</strong></p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/users/users.module.ts</span>
 <span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { TypeOrmModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/typeorm'</span>;
 <span class="hljs-keyword">import</span> { UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.service'</span>;
 <span class="hljs-keyword">import</span> { UsersController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.controller'</span>;
 <span class="hljs-keyword">import</span> { User } <span class="hljs-keyword">from</span> <span class="hljs-string">'./user.entity'</span>;

 <span class="hljs-meta">@Module</span>({
   imports: [TypeOrmModule.forFeature([User])],
   providers: [UsersService],
   controllers: [UsersController],
   <span class="hljs-built_in">exports</span>: [UsersService], <span class="hljs-comment">// if other modules need UsersService</span>
 })
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersModule {}
</code></pre>
</li>
<li><p><strong>Inject the repository:</strong></p>
<p> In the service, inject the <code>Repository&lt;User&gt;</code>:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/users/users.service.ts</span>
 <span class="hljs-keyword">import</span> { Injectable, NotFoundException } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { InjectRepository } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/typeorm'</span>;
 <span class="hljs-keyword">import</span> { Repository } <span class="hljs-keyword">from</span> <span class="hljs-string">'typeorm'</span>;
 <span class="hljs-keyword">import</span> { User } <span class="hljs-keyword">from</span> <span class="hljs-string">'./user.entity'</span>;
 <span class="hljs-keyword">import</span> { CreateUserDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/create-user.dto'</span>;

 <span class="hljs-meta">@Injectable</span>()
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersService {
   <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
     <span class="hljs-meta">@InjectRepository</span>(User)
     <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> userRepository: Repository&lt;User&gt;,
   </span>) {}

   <span class="hljs-keyword">async</span> create(dto: CreateUserDto): <span class="hljs-built_in">Promise</span>&lt;User&gt; {
     <span class="hljs-keyword">const</span> user = <span class="hljs-built_in">this</span>.userRepository.create(dto); <span class="hljs-comment">// maps DTO fields to entity</span>
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.userRepository.save(user);
   }

   <span class="hljs-keyword">async</span> findAll(): <span class="hljs-built_in">Promise</span>&lt;User[]&gt; {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.userRepository.find();
   }

   <span class="hljs-keyword">async</span> findOne(id: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">Promise</span>&lt;User&gt; {
     <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userRepository.findOne({ where: { id } });
     <span class="hljs-keyword">if</span> (!user) {
       <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotFoundException(<span class="hljs-string">`User #<span class="hljs-subst">${id}</span> not found`</span>);
     }
     <span class="hljs-keyword">return</span> user;
   }

   <span class="hljs-keyword">async</span> update(id: <span class="hljs-built_in">number</span>, dto: Partial&lt;CreateUserDto&gt;): <span class="hljs-built_in">Promise</span>&lt;User&gt; {
     <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.findOne(id);
     <span class="hljs-built_in">Object</span>.assign(user, dto);
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.userRepository.save(user);
   }

   <span class="hljs-keyword">async</span> remove(id: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt; {
     <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userRepository.delete(id);
   }
 }
</code></pre>
</li>
<li><p><strong>Use in controller:</strong></p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/users/users.controller.ts</span>
 <span class="hljs-keyword">import</span> { Controller, Get, Post, Body, Param, ParseIntPipe, Put, Delete } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.service'</span>;
 <span class="hljs-keyword">import</span> { CreateUserDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/create-user.dto'</span>;

 <span class="hljs-meta">@Controller</span>(<span class="hljs-string">'users'</span>)
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersController {
   <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> usersService: UsersService</span>) {}

   <span class="hljs-meta">@Post</span>()
   create(<span class="hljs-meta">@Body</span>() dto: CreateUserDto) {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.usersService.create(dto);
   }

   <span class="hljs-meta">@Get</span>()
   findAll() {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.usersService.findAll();
   }

   <span class="hljs-meta">@Get</span>(<span class="hljs-string">':id'</span>)
   findOne(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>, ParseIntPipe) id: <span class="hljs-built_in">number</span>) {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.usersService.findOne(id);
   }

   <span class="hljs-meta">@Put</span>(<span class="hljs-string">':id'</span>)
   update(
     <span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>, ParseIntPipe) id: <span class="hljs-built_in">number</span>,
     <span class="hljs-meta">@Body</span>() dto: Partial&lt;CreateUserDto&gt;,
   ) {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.usersService.update(id, dto);
   }

   <span class="hljs-meta">@Delete</span>(<span class="hljs-string">':id'</span>)
   remove(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>, ParseIntPipe) id: <span class="hljs-built_in">number</span>) {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.usersService.remove(id);
   }
 }
</code></pre>
</li>
<li><p><strong>Migrations (optional but recommended)</strong></p>
<ul>
<li><p>Use TypeORM CLI or programmatic migrations.</p>
</li>
<li><p>Configure a separate <code>ormconfig</code> or supply options in code.</p>
</li>
<li><p>Generate and run migrations to evolve schema without data loss.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-112-mongoose-mongodb">11.2 Mongoose (MongoDB)</h3>
<p>Mongoose is a widely used ODM (Object Document Mapper) for MongoDB. In NestJS, <code>@nestjs/mongoose</code> integrates Mongoose to:</p>
<ul>
<li><p>Define <strong>schemas</strong> via classes and decorators (<code>@Schema()</code>, <code>@Prop()</code>)</p>
</li>
<li><p>Register models in modules with <code>MongooseModule.forFeature()</code></p>
</li>
<li><p>Manage the MongoDB connection with <code>MongooseModule.forRoot()</code></p>
</li>
<li><p>Inject Mongoose <strong>Model</strong> instances into services</p>
</li>
<li><p>Work with documents in a type-safe way (with interfaces/types)</p>
</li>
<li><p>Leverage features like hooks, virtuals, and validation at schema level</p>
</li>
</ul>
<h4 id="heading-when-to-choose-mongoose">When to choose Mongoose</h4>
<p>Mongoose is a good choice if you need a document-oriented, schema-less/ schematized NoSQL store. It’s also great if your data shapes may vary, or you prefer MongoDB’s flexible schema. And it’s helpful if you want features like middleware hooks in schema (pre/post save), virtuals, and so on.</p>
<h4 id="heading-heres-how-to-use-it-1">Here’s how to use it:</h4>
<ol>
<li><p><strong>Install dependencies:</strong></p>
<pre><code class="lang-bash"> npm install --save @nestjs/mongoose mongoose
</code></pre>
</li>
<li><p><strong>Configure root module:</strong></p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/app.module.ts</span>
 <span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { MongooseModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;
 <span class="hljs-keyword">import</span> { CatsModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./cats/cats.module'</span>;

 <span class="hljs-meta">@Module</span>({
   imports: [
     MongooseModule.forRoot(process.env.MONGO_URI || <span class="hljs-string">'mongodb://localhost/nest'</span>),
     CatsModule,
     <span class="hljs-comment">// ...other modules</span>
   ],
 })
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule {}
</code></pre>
</li>
<li><p><strong>Define a schema and document:</strong></p>
<p> Use decorators and interfaces:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/cats/schemas/cat.schema.ts</span>
 <span class="hljs-keyword">import</span> { Prop, Schema, SchemaFactory } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;
 <span class="hljs-keyword">import</span> { Document } <span class="hljs-keyword">from</span> <span class="hljs-string">'mongoose'</span>;

 <span class="hljs-meta">@Schema</span>({ timestamps: <span class="hljs-literal">true</span> })
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> Cat <span class="hljs-keyword">extends</span> Document {
   <span class="hljs-meta">@Prop</span>({ required: <span class="hljs-literal">true</span> })
   name: <span class="hljs-built_in">string</span>;

   <span class="hljs-meta">@Prop</span>()
   age: <span class="hljs-built_in">number</span>;

   <span class="hljs-meta">@Prop</span>()
   breed: <span class="hljs-built_in">string</span>;
 }

 <span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> CatSchema = SchemaFactory.createForClass(Cat);
</code></pre>
<ul>
<li><p>Extending <code>Document</code> gives the Mongoose document methods and properties.</p>
</li>
<li><p><code>timestamps: true</code> auto-adds <code>createdAt</code> and <code>updatedAt</code>.</p>
</li>
<li><p>You can add hooks:</p>
<pre><code class="lang-typescript">  CatSchema.pre&lt;Cat&gt;(<span class="hljs-string">'save'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">next</span>) </span>{
    <span class="hljs-comment">// e.g., modify data or log before saving</span>
    next();
  });
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Set up feature module:</strong></p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/cats/cats.module.ts</span>
 <span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { MongooseModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;
 <span class="hljs-keyword">import</span> { CatsService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./cats.service'</span>;
 <span class="hljs-keyword">import</span> { CatsController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./cats.controller'</span>;
 <span class="hljs-keyword">import</span> { Cat, CatSchema } <span class="hljs-keyword">from</span> <span class="hljs-string">'./schemas/cat.schema'</span>;

 <span class="hljs-meta">@Module</span>({
   imports: [
     MongooseModule.forFeature([{ name: Cat.name, schema: CatSchema }]),
   ],
   controllers: [CatsController],
   providers: [CatsService],
 })
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CatsModule {}
</code></pre>
</li>
<li><p><strong>Inject the model:</strong></p>
<p> In the service, inject <code>Model&lt;Cat&gt;</code>:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/cats/cats.service.ts</span>
 <span class="hljs-keyword">import</span> { Injectable, NotFoundException } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { InjectModel } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;
 <span class="hljs-keyword">import</span> { Model } <span class="hljs-keyword">from</span> <span class="hljs-string">'mongoose'</span>;
 <span class="hljs-keyword">import</span> { Cat } <span class="hljs-keyword">from</span> <span class="hljs-string">'./schemas/cat.schema'</span>;
 <span class="hljs-keyword">import</span> { CreateCatDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/create-cat.dto'</span>;
 <span class="hljs-keyword">import</span> { UpdateCatDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/update-cat.dto'</span>;

 <span class="hljs-meta">@Injectable</span>()
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CatsService {
   <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
     <span class="hljs-meta">@InjectModel</span>(Cat.name) <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> catModel: Model&lt;Cat&gt;,
   </span>) {}

   <span class="hljs-keyword">async</span> create(dto: CreateCatDto): <span class="hljs-built_in">Promise</span>&lt;Cat&gt; {
     <span class="hljs-keyword">const</span> created = <span class="hljs-keyword">new</span> <span class="hljs-built_in">this</span>.catModel(dto);
     <span class="hljs-keyword">return</span> created.save();
   }

   <span class="hljs-keyword">async</span> findAll(): <span class="hljs-built_in">Promise</span>&lt;Cat[]&gt; {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.catModel.find().exec();
   }

   <span class="hljs-keyword">async</span> findOne(id: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">Promise</span>&lt;Cat&gt; {
     <span class="hljs-keyword">const</span> cat = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.catModel.findById(id).exec();
     <span class="hljs-keyword">if</span> (!cat) {
       <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotFoundException(<span class="hljs-string">`Cat <span class="hljs-subst">${id}</span> not found`</span>);
     }
     <span class="hljs-keyword">return</span> cat;
   }

   <span class="hljs-keyword">async</span> update(id: <span class="hljs-built_in">string</span>, dto: UpdateCatDto): <span class="hljs-built_in">Promise</span>&lt;Cat&gt; {
     <span class="hljs-keyword">const</span> updated = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.catModel
       .findByIdAndUpdate(id, dto, { <span class="hljs-keyword">new</span>: <span class="hljs-literal">true</span> })
       .exec();
     <span class="hljs-keyword">if</span> (!updated) {
       <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotFoundException(<span class="hljs-string">`Cat <span class="hljs-subst">${id}</span> not found`</span>);
     }
     <span class="hljs-keyword">return</span> updated;
   }

   <span class="hljs-keyword">async</span> remove(id: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt; {
     <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.catModel.findByIdAndDelete(id).exec();
     <span class="hljs-keyword">if</span> (!res) {
       <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotFoundException(<span class="hljs-string">`Cat <span class="hljs-subst">${id}</span> not found`</span>);
     }
   }
 }
</code></pre>
</li>
<li><p><strong>Use in controller:</strong></p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/cats/cats.controller.ts</span>
 <span class="hljs-keyword">import</span> { Controller, Get, Post, Body, Param, Put, Delete } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { CatsService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./cats.service'</span>;
 <span class="hljs-keyword">import</span> { CreateCatDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/create-cat.dto'</span>;
 <span class="hljs-keyword">import</span> { UpdateCatDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/update-cat.dto'</span>;

 <span class="hljs-meta">@Controller</span>(<span class="hljs-string">'cats'</span>)
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CatsController {
   <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> catsService: CatsService</span>) {}

   <span class="hljs-meta">@Post</span>()
   create(<span class="hljs-meta">@Body</span>() dto: CreateCatDto) {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.catsService.create(dto);
   }

   <span class="hljs-meta">@Get</span>()
   findAll() {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.catsService.findAll();
   }

   <span class="hljs-meta">@Get</span>(<span class="hljs-string">':id'</span>)
   findOne(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>) id: <span class="hljs-built_in">string</span>) {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.catsService.findOne(id);
   }

   <span class="hljs-meta">@Put</span>(<span class="hljs-string">':id'</span>)
   update(
     <span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>) id: <span class="hljs-built_in">string</span>,
     <span class="hljs-meta">@Body</span>() dto: UpdateCatDto,
   ) {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.catsService.update(id, dto);
   }

   <span class="hljs-meta">@Delete</span>(<span class="hljs-string">':id'</span>)
   remove(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>) id: <span class="hljs-built_in">string</span>) {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.catsService.remove(id);
   }
 }
</code></pre>
</li>
<li><p><strong>Advanced Mongoose features</strong></p>
<ul>
<li><p><strong>Virtuals</strong>: define computed properties not stored in DB.</p>
</li>
<li><p><strong>Indexes</strong>: via schema options or <code>@Prop({ index: true })</code>.</p>
</li>
<li><p><strong>Populate</strong>: reference other collections with <code>@Prop({ type: Types.ObjectId, ref: 'OtherModel' })</code>.</p>
</li>
<li><p><strong>Transactions</strong>: use MongoDB sessions for multi-document atomic operations.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-113-prisma">11.3 Prisma</h3>
<p>Prisma is a modern ORM/Query Builder that generates a type-safe client based on a schema definition. It supports relational databases (PostgreSQL, MySQL, SQLite, SQL Server, and more).</p>
<p>Here are some of its key features:</p>
<ul>
<li><p><strong>Type-safe queries</strong>: Autogenerated TypeScript definitions prevent many runtime errors.</p>
</li>
<li><p><strong>Prisma schema</strong>: A declarative <code>.prisma</code> file to define models, relations, and enums.</p>
</li>
<li><p><strong>Migrations</strong>: <code>prisma migrate</code> for evolving schema.</p>
</li>
<li><p><strong>Performance</strong>: Lean query builder without heavy runtime overhead.</p>
</li>
<li><p><strong>Flexibility</strong>: Supports raw queries when needed.</p>
</li>
</ul>
<h4 id="heading-when-to-choose-prisma">When to choose Prisma</h4>
<p>Prisma is a great choice if you prefer a schema-first approach with a clear DSL and auto-generated type-safe client. It’s also great if you want modern features like efficient migrations, rich type inference, and a straightforward developer experience. And it’s a solid choice if you don’t need Active Record pattern. Instead, you use the Prisma client in services.</p>
<h4 id="heading-heres-how-it-works">Here’s how it works:</h4>
<ol>
<li><p><strong>Install dependencies and initialize:</strong></p>
<pre><code class="lang-bash"> npm install @prisma/client
 npm install -D prisma
 npx prisma init
</code></pre>
<p> This creates a <code>prisma/schema.prisma</code> file and a <code>.env</code> with <code>DATABASE_URL</code>.</p>
</li>
<li><p><strong>Define the schema:</strong></p>
<p> In <code>prisma/schema.prisma</code>:</p>
<pre><code class="lang-bash"> datasource db {
   provider = <span class="hljs-string">"postgresql"</span>
   url      = env(<span class="hljs-string">"DATABASE_URL"</span>)
 }

 generator client {
   provider = <span class="hljs-string">"prisma-client-js"</span>
 }

 model User {
   id        Int      @id @default(autoincrement())
   email     String   @unique
   name      String?
   posts     Post[]
   createdAt DateTime @default(now())
   updatedAt DateTime @updatedAt
 }

 model Post {
   id        Int      @id @default(autoincrement())
   title     String
   content   String?
   author    User     @relation(fields: [authorId], references: [id])
   authorId  Int
   published Boolean  @default(<span class="hljs-literal">false</span>)
   createdAt DateTime @default(now())
   updatedAt DateTime @updatedAt
 }
</code></pre>
</li>
<li><p><strong>Run migrations and generate client:</strong></p>
<pre><code class="lang-bash"> npx prisma migrate dev --name init
 npx prisma generate
</code></pre>
<p> This updates the database schema and regenerates the TypeScript client.</p>
</li>
<li><p><strong>Create a PrismaService in NestJS:</strong></p>
<p> A common pattern is to wrap the <code>PrismaClient</code> in an injectable service, handling lifecycle hooks.</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/prisma/prisma.service.ts</span>
 <span class="hljs-keyword">import</span> { Injectable, OnModuleInit, OnModuleDestroy } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@prisma/client'</span>;

 <span class="hljs-meta">@Injectable</span>()
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> PrismaService <span class="hljs-keyword">extends</span> PrismaClient <span class="hljs-keyword">implements</span> OnModuleInit, OnModuleDestroy {
   <span class="hljs-keyword">async</span> onModuleInit() {
     <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.$connect();
   }

   <span class="hljs-keyword">async</span> onModuleDestroy() {
     <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.$disconnect();
   }
 }
</code></pre>
</li>
<li><p><strong>Register PrismaService in a module:</strong></p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/prisma/prisma.module.ts</span>
 <span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { PrismaService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./prisma.service'</span>;

 <span class="hljs-meta">@Module</span>({
   providers: [PrismaService],
   <span class="hljs-built_in">exports</span>: [PrismaService],
 })
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> PrismaModule {}
</code></pre>
<p> Then import <code>PrismaModule</code> in any feature module needing DB access.</p>
</li>
<li><p><strong>Use in a feature service:</strong></p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/users/users.service.ts</span>
 <span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { PrismaService } <span class="hljs-keyword">from</span> <span class="hljs-string">'../prisma/prisma.service'</span>;
 <span class="hljs-keyword">import</span> { CreateUserDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/create-user.dto'</span>;

 <span class="hljs-meta">@Injectable</span>()
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersService {
   <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> prisma: PrismaService</span>) {}

   <span class="hljs-keyword">async</span> create(dto: CreateUserDto) {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.prisma.user.create({ data: dto });
   }

   <span class="hljs-keyword">async</span> findAll() {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.prisma.user.findMany();
   }

   <span class="hljs-keyword">async</span> findOne(id: <span class="hljs-built_in">number</span>) {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.prisma.user.findUnique({ where: { id } });
   }

   <span class="hljs-keyword">async</span> update(id: <span class="hljs-built_in">number</span>, dto: Partial&lt;CreateUserDto&gt;) {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.prisma.user.update({
       where: { id },
       data: dto,
     });
   }

   <span class="hljs-keyword">async</span> remove(id: <span class="hljs-built_in">number</span>) {
     <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.prisma.user.delete({ where: { id } });
     <span class="hljs-keyword">return</span> { deleted: <span class="hljs-literal">true</span> };
   }
 }
</code></pre>
<p> Note: DTO fields must align with Prisma schema types. Prisma client methods return typed results.</p>
</li>
<li><p><strong>Inject in controller:</strong></p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/users/users.controller.ts</span>
 <span class="hljs-keyword">import</span> { Controller, Get, Post, Body, Param, ParseIntPipe, Put, Delete } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.service'</span>;
 <span class="hljs-keyword">import</span> { CreateUserDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/create-user.dto'</span>;

 <span class="hljs-meta">@Controller</span>(<span class="hljs-string">'users'</span>)
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersController {
   <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> usersService: UsersService</span>) {}

   <span class="hljs-meta">@Post</span>()
   create(<span class="hljs-meta">@Body</span>() dto: CreateUserDto) {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.usersService.create(dto);
   }

   <span class="hljs-meta">@Get</span>()
   findAll() {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.usersService.findAll();
   }

   <span class="hljs-meta">@Get</span>(<span class="hljs-string">':id'</span>)
   findOne(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>, ParseIntPipe) id: <span class="hljs-built_in">number</span>) {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.usersService.findOne(id);
   }

   <span class="hljs-meta">@Put</span>(<span class="hljs-string">':id'</span>)
   update(
     <span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>, ParseIntPipe) id: <span class="hljs-built_in">number</span>,
     <span class="hljs-meta">@Body</span>() dto: Partial&lt;CreateUserDto&gt;,
   ) {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.usersService.update(id, dto);
   }

   <span class="hljs-meta">@Delete</span>(<span class="hljs-string">':id'</span>)
   remove(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>, ParseIntPipe) id: <span class="hljs-built_in">number</span>) {
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.usersService.remove(id);
   }
 }
</code></pre>
</li>
<li><p><strong>Advanced Prisma usage</strong></p>
<ul>
<li><p><strong>Relations and nested writes</strong>: for example, create a post with nested author connect/create.</p>
</li>
<li><p><strong>Transactions</strong>: <code>this.prisma.$transaction([...])</code> for atomic operations.</p>
</li>
<li><p><strong>Raw queries</strong>: <code>this.prisma.$queryRaw</code> when needed.</p>
</li>
<li><p><strong>Middleware</strong>: Prisma supports middlewares on the client side.</p>
</li>
<li><p><strong>Performance tuning</strong>: select only needed fields, use pagination patterns.</p>
</li>
</ul>
</li>
</ol>
<p>With these three approaches, you can choose the database integration strategy that best fits your application’s needs:</p>
<ul>
<li><p><strong>TypeORM</strong> for a full-fledged ORM with decorators and migrations support in relational databases.</p>
</li>
<li><p><strong>Mongoose</strong> for flexible document schemas in MongoDB.</p>
</li>
<li><p><strong>Prisma</strong> for a modern, type-safe query builder/ORM alternative with excellent developer ergonomics.</p>
</li>
</ul>
<p>In the next section, we’ll cover <strong>Configuration Management</strong> – how to handle environment variables and config modules in NestJS.</p>
<h2 id="heading-12-configuration-management">12. Configuration Management</h2>
<p>Managing configuration cleanly is crucial for applications to behave correctly across environments (development, staging, production). NestJS provides the <code>@nestjs/config</code> module to centralize configuration loading, validation, and injection.</p>
<h3 id="heading-121-nestjsconfig-module">12.1 @nestjs/config Module</h3>
<p>The <code>@nestjs/config</code> module is a powerful utility for managing application configuration settings. Here are some of its key features:</p>
<ul>
<li><p><strong>Centralized config</strong>: Instead of sprinkling <code>process.env</code> throughout your code, it uses a dedicated service that loads and validates configuration once at startup.</p>
</li>
<li><p><strong>Environment agnostic</strong>: It loads variables from <code>.env</code> files, environment variables, or other sources, with support for different files per environment.</p>
</li>
<li><p><strong>Validation</strong>: It integrates a schema (for example, via Joi) to ensure required variables are present and correctly typed, failing fast if misconfigured.</p>
</li>
<li><p><strong>Config Namespacing</strong>: It organizes related settings into logical groups (for example, database, auth, third-party APIs) via configuration factories.</p>
</li>
<li><p><strong>Injection</strong>: It injects a <code>ConfigService</code> to read config values in services or modules, with type safety when using custom typed wrappers.</p>
</li>
</ul>
<h4 id="heading-heres-how-it-works-1">Here’s how it works:</h4>
<ol>
<li><p><strong>Install the package</strong></p>
<pre><code class="lang-bash"> npm install @nestjs/config
 npm install joi    <span class="hljs-comment"># if you plan to validate via Joi schemas</span>
</code></pre>
</li>
<li><p><strong>Import and initialize ConfigModule</strong></p>
<p> In your root module (<code>AppModule</code>), import <code>ConfigModule.forRoot()</code>. Typical options:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/app.module.ts</span>
 <span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { ConfigModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/config'</span>;
 <span class="hljs-keyword">import</span> configuration <span class="hljs-keyword">from</span> <span class="hljs-string">'./config/configuration'</span>;
 <span class="hljs-keyword">import</span> { validationSchema } <span class="hljs-keyword">from</span> <span class="hljs-string">'./config/validation'</span>;

 <span class="hljs-meta">@Module</span>({
   imports: [
     ConfigModule.forRoot({
       <span class="hljs-comment">// Load .env automatically; specify envFilePath if custom:</span>
       isGlobal: <span class="hljs-literal">true</span>,           <span class="hljs-comment">// makes ConfigService available app-wide</span>
       envFilePath: [<span class="hljs-string">'.env.development.local'</span>, <span class="hljs-string">'.env.development'</span>, <span class="hljs-string">'.env'</span>], 
       load: [configuration],    <span class="hljs-comment">// optional: load custom config factory(s)</span>
       validationSchema,         <span class="hljs-comment">// optional: Joi schema to validate env vars</span>
       validationOptions: {
         allowUnknown: <span class="hljs-literal">true</span>,
         abortEarly: <span class="hljs-literal">true</span>,
       },
     }),
     <span class="hljs-comment">// ...other modules</span>
   ],
 })
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule {}
</code></pre>
<ul>
<li><p><code>isGlobal: true</code> avoids importing <code>ConfigModule</code> in every feature module.</p>
</li>
<li><p><code>envFilePath</code>: an array lets you try multiple files (for example, local overrides before default).</p>
</li>
<li><p><code>load</code>: array of functions returning partial config objects – see next step.</p>
</li>
<li><p><code>validationSchema</code>: a Joi schema ensuring required variables exist and are correct type/format.</p>
</li>
</ul>
</li>
<li><p><strong>Define a configuration factory</strong></p>
<p> Organize related settings into a typed object:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/config/configuration.ts</span>
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> () =&gt; ({
   port: <span class="hljs-built_in">parseInt</span>(process.env.PORT, <span class="hljs-number">10</span>) || <span class="hljs-number">3000</span>,
   database: {
     host: process.env.DB_HOST,
     port: <span class="hljs-built_in">parseInt</span>(process.env.DB_PORT, <span class="hljs-number">10</span>) || <span class="hljs-number">5432</span>,
     user: process.env.DB_USER,
     pass: process.env.DB_PASS,
     name: process.env.DB_NAME,
   },
   jwt: {
     secret: process.env.JWT_SECRET,
     expiresIn: process.env.JWT_EXPIRES_IN || <span class="hljs-string">'1h'</span>,
   },
   <span class="hljs-comment">// add other namespaces as needed</span>
 });
</code></pre>
</li>
<li><p><strong>Validate environment variables</strong></p>
<p> Using Joi for validation:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/config/validation.ts</span>
 <span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> Joi <span class="hljs-keyword">from</span> <span class="hljs-string">'joi'</span>;

 <span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> validationSchema = Joi.object({
   NODE_ENV: Joi.string()
     .valid(<span class="hljs-string">'development'</span>, <span class="hljs-string">'production'</span>, <span class="hljs-string">'test'</span>, <span class="hljs-string">'staging'</span>)
     .default(<span class="hljs-string">'development'</span>),
   PORT: Joi.number().default(<span class="hljs-number">3000</span>),
   DB_HOST: Joi.string().required(),
   DB_PORT: Joi.number().default(<span class="hljs-number">5432</span>),
   DB_USER: Joi.string().required(),
   DB_PASS: Joi.string().required(),
   DB_NAME: Joi.string().required(),
   JWT_SECRET: Joi.string().min(<span class="hljs-number">32</span>).required(),
   JWT_EXPIRES_IN: Joi.string().default(<span class="hljs-string">'1h'</span>),
   <span class="hljs-comment">// add other variables...</span>
 });
</code></pre>
<p> If validation fails at startup, the application will error out with details, preventing misconfigured deployments.</p>
</li>
<li><p><strong>Inject ConfigService</strong></p>
<p> Anywhere you need config, inject <code>ConfigService</code>:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/some/some.service.ts</span>
 <span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { ConfigService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/config'</span>;

 <span class="hljs-meta">@Injectable</span>()
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> SomeService {
   <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> configService: ConfigService</span>) {}

   getDbConfig() {
     <span class="hljs-keyword">const</span> host = <span class="hljs-built_in">this</span>.configService.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'database.host'</span>);
     <span class="hljs-keyword">const</span> port = <span class="hljs-built_in">this</span>.configService.get&lt;<span class="hljs-built_in">number</span>&gt;(<span class="hljs-string">'database.port'</span>);
     <span class="hljs-comment">// Use these values to configure a database client, etc.</span>
     <span class="hljs-keyword">return</span> { host, port };
   }
 }
</code></pre>
<ul>
<li><p>Use dot notation for nested config: for example, <code>'jwt.secret'</code>.</p>
</li>
<li><p>You can also read raw env vars via <code>configService.get&lt;string&gt;('DB_HOST')</code> if needed, but preferring structured config is clearer.</p>
</li>
</ul>
</li>
<li><p><strong>Typed wrapper for ConfigService (optional)</strong></p>
<p> For stronger typing, create an interface matching your configuration and a wrapper:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/config/config.interface.ts</span>
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> AppConfig {
   port: <span class="hljs-built_in">number</span>;
   database: {
     host: <span class="hljs-built_in">string</span>;
     port: <span class="hljs-built_in">number</span>;
     user: <span class="hljs-built_in">string</span>;
     pass: <span class="hljs-built_in">string</span>;
     name: <span class="hljs-built_in">string</span>;
   };
   jwt: {
     secret: <span class="hljs-built_in">string</span>;
     expiresIn: <span class="hljs-built_in">string</span>;
   };
 }
</code></pre>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/config/typed-config.service.ts</span>
 <span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { ConfigService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/config'</span>;
 <span class="hljs-keyword">import</span> { AppConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'./config.interface'</span>;

 <span class="hljs-meta">@Injectable</span>()
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> TypedConfigService {
   <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> configService: ConfigService</span>) {}

   get appConfig(): AppConfig {
     <span class="hljs-keyword">return</span> {
       port: <span class="hljs-built_in">this</span>.configService.get&lt;<span class="hljs-built_in">number</span>&gt;(<span class="hljs-string">'port'</span>),
       database: {
         host: <span class="hljs-built_in">this</span>.configService.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'database.host'</span>),
         port: <span class="hljs-built_in">this</span>.configService.get&lt;<span class="hljs-built_in">number</span>&gt;(<span class="hljs-string">'database.port'</span>),
         user: <span class="hljs-built_in">this</span>.configService.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'database.user'</span>),
         pass: <span class="hljs-built_in">this</span>.configService.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'database.pass'</span>),
         name: <span class="hljs-built_in">this</span>.configService.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'database.name'</span>),
       },
       jwt: {
         secret: <span class="hljs-built_in">this</span>.configService.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'jwt.secret'</span>),
         expiresIn: <span class="hljs-built_in">this</span>.configService.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'jwt.expiresIn'</span>),
       },
     };
   }
 }
</code></pre>
<p> Register <code>TypedConfigService</code> in a module if you prefer injecting it instead of raw <code>ConfigService</code>.</p>
</li>
<li><p><strong>Dynamic module registration using config</strong></p>
<p> Many Nest modules accept dynamic options. For example, TypeORM:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/database/database.module.ts</span>
 <span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { TypeOrmModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/typeorm'</span>;
 <span class="hljs-keyword">import</span> { ConfigService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/config'</span>;

 <span class="hljs-meta">@Module</span>({
   imports: [
     TypeOrmModule.forRootAsync({
       inject: [ConfigService],
       useFactory: <span class="hljs-function">(<span class="hljs-params">config: ConfigService</span>) =&gt;</span> ({
         <span class="hljs-keyword">type</span>: <span class="hljs-string">'postgres'</span>,
         host: config.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'database.host'</span>),
         port: config.get&lt;<span class="hljs-built_in">number</span>&gt;(<span class="hljs-string">'database.port'</span>),
         username: config.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'database.user'</span>),
         password: config.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'database.pass'</span>),
         database: config.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'database.name'</span>),
         entities: [__dirname + <span class="hljs-string">'/../**/*.entity{.ts,.js}'</span>],
         synchronize: config.get(<span class="hljs-string">'NODE_ENV'</span>) !== <span class="hljs-string">'production'</span>,
       }),
     }),
   ],
 })
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> DatabaseModule {}
</code></pre>
<p> Using <code>forRootAsync</code> with <code>useFactory</code> ensures config is loaded before the module initializes.</p>
</li>
</ol>
<h3 id="heading-122-environment-variables">12.2 Environment Variables</h3>
<p>Environment variables serve as the bridge between code and its runtime environment, letting you decouple configuration (like database URLs, API keys, or feature flags) from your source.</p>
<p>By relying on environment variables, you ensure that the same application bundle can run safely across development, staging, and production – each providing its own sensitive or environment-specific settings without changing code. This is how it works:</p>
<ul>
<li><p><strong>12-Factor app principle</strong>: Stores config in the environment. Avoids hard-coding secrets or environment-specific settings in code.</p>
</li>
<li><p><strong>Separation of concerns</strong>: Code remains the same across environments. Behavior is driven by env vars or config files.</p>
</li>
<li><p><strong>Security</strong>: Keeps secrets (API keys, DB passwords) out of source control. Uses environment variables or secure vaults.</p>
</li>
<li><p><strong>Overrides and precedence</strong>: You may have multiple <code>.env</code> files (for example, <code>.env</code>, <code>.env.local</code>, <code>.env.production</code>) or CI/CD provided vars. It controls the order of loading.</p>
</li>
<li><p><strong>Defaults and fallbacks</strong>: Provides sensible defaults in code or config factories so the app can run in development without requiring every variable.</p>
</li>
</ul>
<h4 id="heading-heres-how-to-use-it-2">Here’s how to use it:</h4>
<ol>
<li><p><strong>.env files</strong></p>
<ul>
<li><p>Create a <code>.env</code> file at project root with key-value pairs:</p>
<pre><code class="lang-typescript">  PORT=<span class="hljs-number">3000</span>
  DB_HOST=localhost
  DB_PORT=<span class="hljs-number">5432</span>
  DB_USER=postgres
  DB_PASS=secret
  DB_NAME=mydb
  JWT_SECRET=supersecretjwtkey
  JWT_EXPIRES_IN=<span class="hljs-number">2</span>h
</code></pre>
</li>
<li><p>Optionally create <code>.env.development</code>, <code>.env.test</code>, <code>.env.production</code>, and load them based on <code>NODE_ENV</code>.</p>
</li>
<li><p>Ensure <code>.env</code> files are in <code>.gitignore</code> to avoid committing secrets.</p>
</li>
</ul>
</li>
<li><p><strong>Loading order</strong></p>
<ul>
<li><p>With <code>@nestjs/config</code>, specify <code>envFilePath</code> as an array, for example:</p>
<pre><code class="lang-typescript">  ConfigModule.forRoot({
    envFilePath: [
      <span class="hljs-string">`.env.<span class="hljs-subst">${process.env.NODE_ENV}</span>.local`</span>,
      <span class="hljs-string">`.env.<span class="hljs-subst">${process.env.NODE_ENV}</span>`</span>,
      <span class="hljs-string">`.env`</span>,
    ],
    isGlobal: <span class="hljs-literal">true</span>,
  });
</code></pre>
</li>
<li><p>This tries <code>.env.development.local</code>, then <code>.env.development</code>, then <code>.env</code>. CI/CD can set actual environment variables that override values in files.</p>
</li>
</ul>
</li>
<li><p><strong>Accessing raw environment variables</strong></p>
<ul>
<li><p>While structured config is preferred, sometimes you need direct access:</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">const</span> raw = process.env.SOME_VAR;
</code></pre>
</li>
<li><p>Avoid scattering <code>process.env</code> in multiple places. Instead, prefer reading once in configuration factory and injecting via <code>ConfigService</code>.</p>
</li>
</ul>
</li>
<li><p><strong>Default values</strong></p>
<ul>
<li><p>In configuration factory or when reading via <code>ConfigService</code>, provide defaults:</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">const</span> port = configService.get&lt;<span class="hljs-built_in">number</span>&gt;(<span class="hljs-string">'PORT'</span>, <span class="hljs-number">3000</span>);
</code></pre>
<p>  or in factory:</p>
<pre><code class="lang-typescript">  port: <span class="hljs-built_in">parseInt</span>(process.env.PORT, <span class="hljs-number">10</span>) || <span class="hljs-number">3000</span>
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Type coercion</strong></p>
<ul>
<li><p>Environment variables are strings by default. Convert to numbers or booleans as needed:</p>
<pre><code class="lang-typescript">  <span class="hljs-keyword">const</span> isProd = configService.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'NODE_ENV'</span>) === <span class="hljs-string">'production'</span>;
  <span class="hljs-keyword">const</span> enableFeature = configService.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'FEATURE_FLAG'</span>) === <span class="hljs-string">'true'</span>;
  <span class="hljs-keyword">const</span> timeout = <span class="hljs-built_in">parseInt</span>(configService.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'TIMEOUT_MS'</span>), <span class="hljs-number">10</span>) || <span class="hljs-number">5000</span>;
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Secret management</strong></p>
<ul>
<li><p>For sensitive data in production, consider using secret managers (AWS Secrets Manager, Vault) instead of plain <code>.env</code>. In that case, load secrets at startup (for example, via a custom provider or factory) and merge into the configuration.</p>
</li>
<li><p>Example: in <code>useFactory</code>, asynchronously fetch secrets and return a config object including them.</p>
</li>
</ul>
</li>
<li><p><strong>Runtime configuration changes</strong></p>
<ul>
<li>Generally configs are static at startup. If you need to reload config without restarting, implement a custom mechanism (for example, read from a database or remote config service periodically). Inject a service that fetches and caches values, but note this departs from 12-factor principles.</li>
</ul>
</li>
<li><p><strong>Validation in production</strong></p>
<ul>
<li><p>Always validate required env vars at startup so misconfigurations fail early. Use <code>validationSchema</code> with Joi or another validator.</p>
</li>
<li><p>Example error: if <code>JWT_SECRET</code> is missing or too short, the app should refuse to start, logging a clear error.</p>
</li>
</ul>
</li>
</ol>
<p>With configuration managed via <code>@nestjs/config</code> and environment variables, your NestJS app can adapt seamlessly across environments, keep secrets secure, and avoid environment-specific code changes. In the next section, we’ll cover <strong>Authentication</strong> strategies (JWT, OAuth2/social login).</p>
<h2 id="heading-13-authentication">13. Authentication</h2>
<p>Handling authentication securely is a common requirement. In NestJS, you typically use <strong>Passport</strong> strategies alongside the <strong>@nestjs/jwt</strong> module for JWT-based flows, or OAuth2 strategies for social login.</p>
<p>Here, we’ll cover two common approaches:</p>
<ul>
<li><p><strong>JWT Strategy</strong>: token-based authentication for APIs.</p>
</li>
<li><p><strong>OAuth2 / Social Login</strong>: integrating providers like Google or GitHub.</p>
</li>
</ul>
<h3 id="heading-131-jwt-strategy">13.1 JWT Strategy</h3>
<p>JSON Web Tokens (JWTs) are a compact, URL-safe means of representing claims between two parties. In an authentication context, the server issues a signed token containing user identity and possibly other claims, while the client stores and sends this token on subsequent requests (typically in the <code>Authorization: Bearer &lt;token&gt;</code> header).</p>
<p>Because the token is signed (and optionally encrypted), the server can verify its integrity and authenticity without needing to maintain session state in memory or a database. This stateless nature simplifies scaling and decouples services.</p>
<p>Tokens include an expiration (<code>exp</code>) so they automatically become invalid after a certain time. For longer-lived sessions, you can layer a refresh-token pattern on top.</p>
<p>In NestJS, we leverage <code>@nestjs/jwt</code> to sign and verify tokens and <code>@nestjs/passport</code> with <code>passport-jwt</code> to integrate a guard that checks incoming tokens. Below is how it works.</p>
<ul>
<li><p><strong>JWT (JSON Web Token)</strong>: a signed token containing claims (for example, user ID) that clients send in the <code>Authorization</code> header.</p>
</li>
<li><p><strong>Stateless</strong>: the server verifies the token signature without storing session state.</p>
</li>
<li><p><strong>Expiration</strong>: embed expiry (<code>exp</code>) so tokens auto-expire; possibly use refresh tokens for long-lived sessions.</p>
</li>
<li><p>In NestJS, you use <code>@nestjs/jwt</code> to sign/verify tokens and <code>@nestjs/passport</code> with <code>passport-jwt</code> to implement the guard.</p>
</li>
</ul>
<h4 id="heading-heres-how-to-use-it-3">Here’s how to use it:</h4>
<ol>
<li><p><strong>Install dependencies</strong></p>
<pre><code class="lang-bash"> npm install @nestjs/jwt passport-jwt @nestjs/passport passport
</code></pre>
</li>
<li><p><strong>Configuration</strong></p>
<p> Use <code>ConfigService</code> (from previous section) to load secrets and TTL:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/auth/auth.config.ts</span>
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> () =&gt; ({
   jwt: {
     secret: process.env.JWT_SECRET || <span class="hljs-string">'default-secret'</span>,
     expiresIn: process.env.JWT_EXPIRES_IN || <span class="hljs-string">'1h'</span>,
   },
 });
</code></pre>
<p> Ensure <code>ConfigModule.forRoot({ load: [authConfig], isGlobal: true, validationSchema: ... })</code> is set in <code>AppModule</code>.</p>
</li>
<li><p><strong>AuthModule setup</strong></p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/auth/auth.module.ts</span>
 <span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { JwtModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/jwt'</span>;
 <span class="hljs-keyword">import</span> { PassportModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/passport'</span>;
 <span class="hljs-keyword">import</span> { ConfigService, ConfigModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/config'</span>;
 <span class="hljs-keyword">import</span> { JwtStrategy } <span class="hljs-keyword">from</span> <span class="hljs-string">'./jwt.strategy'</span>;
 <span class="hljs-keyword">import</span> { AuthService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./auth.service'</span>;
 <span class="hljs-keyword">import</span> { UsersModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'../users/users.module'</span>; <span class="hljs-comment">// assumes a UsersService</span>

 <span class="hljs-meta">@Module</span>({
   imports: [
     UsersModule,
     PassportModule.register({ defaultStrategy: <span class="hljs-string">'jwt'</span> }),
     JwtModule.registerAsync({
       imports: [ConfigModule],
       inject: [ConfigService],
       useFactory: <span class="hljs-function">(<span class="hljs-params">config: ConfigService</span>) =&gt;</span> ({
         secret: config.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'jwt.secret'</span>),
         signOptions: { expiresIn: config.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'jwt.expiresIn'</span>) },
       }),
     }),
   ],
   providers: [AuthService, JwtStrategy],
   <span class="hljs-built_in">exports</span>: [AuthService],
 })
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AuthModule {}
</code></pre>
</li>
<li><p><strong>AuthService</strong></p>
<p> Responsible for validating credentials and issuing tokens:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/auth/auth.service.ts</span>
 <span class="hljs-keyword">import</span> { Injectable, UnauthorizedException } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { JwtService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/jwt'</span>;
 <span class="hljs-keyword">import</span> { UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">'../users/users.service'</span>;
 <span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> bcrypt <span class="hljs-keyword">from</span> <span class="hljs-string">'bcrypt'</span>;

 <span class="hljs-meta">@Injectable</span>()
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AuthService {
   <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
     <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> usersService: UsersService,
     <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> jwtService: JwtService,
   </span>) {}

   <span class="hljs-comment">// Validate user credentials (email/password)</span>
   <span class="hljs-keyword">async</span> validateUser(email: <span class="hljs-built_in">string</span>, pass: <span class="hljs-built_in">string</span>) {
     <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.usersService.findByEmail(email);
     <span class="hljs-keyword">if</span> (user &amp;&amp; (<span class="hljs-keyword">await</span> bcrypt.compare(pass, user.password))) {
       <span class="hljs-comment">// exclude password before returning</span>
       <span class="hljs-keyword">const</span> { password, ...result } = user;
       <span class="hljs-keyword">return</span> result;
     }
     <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
   }

   <span class="hljs-comment">// Called after validateUser succeeds</span>
   <span class="hljs-keyword">async</span> login(user: <span class="hljs-built_in">any</span>) {
     <span class="hljs-keyword">const</span> payload = { sub: user.id, email: user.email };
     <span class="hljs-keyword">return</span> {
       access_token: <span class="hljs-built_in">this</span>.jwtService.sign(payload),
     };
   }
 }
</code></pre>
</li>
<li><p><strong>JwtStrategy</strong></p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/auth/jwt.strategy.ts</span>
 <span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { PassportStrategy } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/passport'</span>;
 <span class="hljs-keyword">import</span> { ExtractJwt, Strategy } <span class="hljs-keyword">from</span> <span class="hljs-string">'passport-jwt'</span>;
 <span class="hljs-keyword">import</span> { ConfigService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/config'</span>;

 <span class="hljs-meta">@Injectable</span>()
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> JwtStrategy <span class="hljs-keyword">extends</span> PassportStrategy(Strategy) {
   <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> configService: ConfigService</span>) {
     <span class="hljs-built_in">super</span>({
       jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
       ignoreExpiration: <span class="hljs-literal">false</span>,
       secretOrKey: configService.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'jwt.secret'</span>),
     });
   }

   <span class="hljs-keyword">async</span> validate(payload: <span class="hljs-built_in">any</span>) {
     <span class="hljs-comment">// payload.sub is user ID</span>
     <span class="hljs-keyword">return</span> { userId: payload.sub, email: payload.email };
     <span class="hljs-comment">// returned value is assigned to req.user</span>
   }
 }
</code></pre>
</li>
<li><p><strong>Auth Controller</strong></p>
<p> Expose login endpoint:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/auth/auth.controller.ts</span>
 <span class="hljs-keyword">import</span> { Controller, Post, Body, Request, UseGuards } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { AuthService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./auth.service'</span>;
 <span class="hljs-keyword">import</span> { LocalAuthGuard } <span class="hljs-keyword">from</span> <span class="hljs-string">'./local-auth.guard'</span>; <span class="hljs-comment">// optional if using local strategy</span>

 <span class="hljs-meta">@Controller</span>(<span class="hljs-string">'auth'</span>)
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AuthController {
   <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> authService: AuthService</span>) {}

   <span class="hljs-comment">// Example: using a local strategy for email/password</span>
   <span class="hljs-meta">@UseGuards</span>(LocalAuthGuard)
   <span class="hljs-meta">@Post</span>(<span class="hljs-string">'login'</span>)
   <span class="hljs-keyword">async</span> login(<span class="hljs-meta">@Request</span>() req) {
     <span class="hljs-comment">// LocalAuthGuard attaches user to req.user</span>
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.authService.login(req.user);
   }

   <span class="hljs-comment">// Alternatively, implement login logic directly:</span>
   <span class="hljs-meta">@Post</span>(<span class="hljs-string">'login-basic'</span>)
   <span class="hljs-keyword">async</span> loginBasic(<span class="hljs-meta">@Body</span>() body: { email: <span class="hljs-built_in">string</span>; password: <span class="hljs-built_in">string</span> }) {
     <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.authService.validateUser(body.email, body.password);
     <span class="hljs-keyword">if</span> (!user) {
       <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnauthorizedException(<span class="hljs-string">'Invalid credentials'</span>);
     }
     <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.authService.login(user);
   }
 }
</code></pre>
<ul>
<li><strong>LocalAuthGuard</strong> would use a LocalStrategy to validate credentials via Passport.</li>
</ul>
</li>
<li><p><strong>Protecting routes</strong></p>
<p> Use the <strong>JwtAuthGuard</strong>:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/auth/jwt-auth.guard.ts</span>
 <span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { AuthGuard } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/passport'</span>;

 <span class="hljs-meta">@Injectable</span>()
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> JwtAuthGuard <span class="hljs-keyword">extends</span> AuthGuard(<span class="hljs-string">'jwt'</span>) {}
</code></pre>
<p> Apply to controllers or routes:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/profile/profile.controller.ts</span>
 <span class="hljs-keyword">import</span> { Controller, Get, UseGuards, Request } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { JwtAuthGuard } <span class="hljs-keyword">from</span> <span class="hljs-string">'../auth/jwt-auth.guard'</span>;

 <span class="hljs-meta">@Controller</span>(<span class="hljs-string">'profile'</span>)
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ProfileController {
   <span class="hljs-meta">@UseGuards</span>(JwtAuthGuard)
   <span class="hljs-meta">@Get</span>()
   getProfile(<span class="hljs-meta">@Request</span>() req) {
     <span class="hljs-keyword">return</span> req.user; <span class="hljs-comment">// { userId, email }</span>
   }
 }
</code></pre>
</li>
<li><p><strong>Refresh Tokens (optional)</strong></p>
<ul>
<li><p>Issue a refresh token (longer expiry) and store it (for example, in DB or as HTTP-only cookie).</p>
</li>
<li><p>Create a separate endpoint to issue new access token when the access token expires.</p>
</li>
<li><p>Verify refresh token validity (for example, compare stored token or a hashed version).</p>
</li>
<li><p>Implementation details vary – consider security best practices (rotate tokens, revoke on logout).</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-132-oauth2-social-login">13.2 OAuth2 / Social Login</h3>
<p>Social login via OAuth2 lets users authenticate with third-party providers (Google, GitHub, Facebook, and so on) without creating a separate password for your service.</p>
<p>Under the Authorization Code Flow, the user is redirected to the provider’s consent screen. After granting permission, the provider redirects back with a temporary code. The backend exchanges this code for access (and optionally refresh) tokens, fetches the user’s profile, and then you can link or create a local user record. Finally, you typically issue your own JWT (or session) so the client can call your secured APIs.</p>
<p>Keeping OAuth client IDs/secrets in environment variables (via <code>ConfigService</code>) ensures security and flexibility. Here’s how it works:</p>
<ul>
<li><p><strong>OAuth2 Authorization Code Flow</strong>: Redirect the user to the provider’s consent screen. The provider redirects back with a code. The back-end exchanges code for tokens and retrieves user info.</p>
</li>
<li><p>In server-side (NestJS) you use Passport strategies (for example, <code>passport-google-oauth20</code>, <code>passport-github2</code>).</p>
</li>
<li><p>After getting user profile from provider, you look up or create a matching local user record, then issue your own JWT or session.</p>
</li>
<li><p>Keep secrets (client ID/secret) in environment variables and load via <code>ConfigService</code>.</p>
</li>
</ul>
<h4 id="heading-heres-how-to-use-it-4">Here’s how to use it:</h4>
<ol>
<li><p><strong>Install dependencies</strong></p>
<pre><code class="lang-bash"> npm install @nestjs/passport passport passport-google-oauth20
 <span class="hljs-comment"># or passport-facebook, passport-github2, etc.</span>
</code></pre>
</li>
<li><p><strong>Configuration</strong></p>
<p> Add OAuth credentials to env and <code>ConfigModule</code>:</p>
<pre><code class="lang-bash"> GOOGLE_CLIENT_ID=your-google-client-id
 GOOGLE_CLIENT_SECRET=your-google-client-secret
 GOOGLE_CALLBACK_URL=http://localhost:3000/auth/google/callback
</code></pre>
</li>
<li><p><strong>OAuth Strategy</strong></p>
<p> Example: Google</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/auth/google.strategy.ts</span>
 <span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { PassportStrategy } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/passport'</span>;
 <span class="hljs-keyword">import</span> { Strategy, VerifyCallback } <span class="hljs-keyword">from</span> <span class="hljs-string">'passport-google-oauth20'</span>;
 <span class="hljs-keyword">import</span> { ConfigService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/config'</span>;
 <span class="hljs-keyword">import</span> { AuthService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./auth.service'</span>;

 <span class="hljs-meta">@Injectable</span>()
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> GoogleStrategy <span class="hljs-keyword">extends</span> PassportStrategy(Strategy, <span class="hljs-string">'google'</span>) {
   <span class="hljs-keyword">constructor</span>(<span class="hljs-params">configService: ConfigService, <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> authService: AuthService</span>) {
     <span class="hljs-built_in">super</span>({
       clientID: configService.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'GOOGLE_CLIENT_ID'</span>),
       clientSecret: configService.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'GOOGLE_CLIENT_SECRET'</span>),
       callbackURL: configService.get&lt;<span class="hljs-built_in">string</span>&gt;(<span class="hljs-string">'GOOGLE_CALLBACK_URL'</span>),
       scope: [<span class="hljs-string">'email'</span>, <span class="hljs-string">'profile'</span>],
     });
   }

   <span class="hljs-keyword">async</span> validate(accessToken: <span class="hljs-built_in">string</span>, refreshToken: <span class="hljs-built_in">string</span>, profile: <span class="hljs-built_in">any</span>, done: VerifyCallback): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">any</span>&gt; {
     <span class="hljs-keyword">const</span> { id, emails, displayName } = profile;
     <span class="hljs-keyword">const</span> email = emails &amp;&amp; emails[<span class="hljs-number">0</span>]?.value;
     <span class="hljs-comment">// Delegate to AuthService to find or create local user</span>
     <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.authService.validateOAuthLogin(<span class="hljs-string">'google'</span>, id, email, displayName);
     done(<span class="hljs-literal">null</span>, user);
   }
 }
</code></pre>
<p> In <code>AuthService</code>:</p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/auth/auth.service.ts (add method)</span>
 <span class="hljs-keyword">async</span> validateOAuthLogin(provider: <span class="hljs-built_in">string</span>, providerId: <span class="hljs-built_in">string</span>, email: <span class="hljs-built_in">string</span>, name?: <span class="hljs-built_in">string</span>) {
   <span class="hljs-comment">// Find existing user by provider+providerId or email</span>
   <span class="hljs-keyword">let</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.usersService.findByProvider(provider, providerId);
   <span class="hljs-keyword">if</span> (!user) {
     <span class="hljs-comment">// Optionally check by email: if exists, link accounts; otherwise create new</span>
     user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.usersService.createOAuthUser({ provider, providerId, email, name });
   }
   <span class="hljs-comment">// Issue JWT or return user object; here we return minimal payload for login</span>
   <span class="hljs-keyword">return</span> user;
 }
</code></pre>
</li>
<li><p><strong>AuthController endpoints</strong></p>
<pre><code class="lang-typescript"> <span class="hljs-comment">// src/auth/auth.controller.ts</span>
 <span class="hljs-keyword">import</span> { Controller, Get, Req, UseGuards } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
 <span class="hljs-keyword">import</span> { AuthGuard } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/passport'</span>;
 <span class="hljs-keyword">import</span> { AuthService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./auth.service'</span>;

 <span class="hljs-meta">@Controller</span>(<span class="hljs-string">'auth'</span>)
 <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AuthController {
   <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> authService: AuthService</span>) {}

   <span class="hljs-meta">@Get</span>(<span class="hljs-string">'google'</span>)
   <span class="hljs-meta">@UseGuards</span>(AuthGuard(<span class="hljs-string">'google'</span>))
   <span class="hljs-keyword">async</span> googleAuth(<span class="hljs-meta">@Req</span>() req) {
     <span class="hljs-comment">// Initiates Google OAuth2 flow</span>
   }

   <span class="hljs-meta">@Get</span>(<span class="hljs-string">'google/callback'</span>)
   <span class="hljs-meta">@UseGuards</span>(AuthGuard(<span class="hljs-string">'google'</span>))
   <span class="hljs-keyword">async</span> googleAuthRedirect(<span class="hljs-meta">@Req</span>() req) {
     <span class="hljs-comment">// Google redirects here after consent; req.user set by GoogleStrategy.validate</span>
     <span class="hljs-keyword">const</span> user = req.user;
     <span class="hljs-comment">// Issue JWT or set a cookie, then redirect or return token</span>
     <span class="hljs-keyword">const</span> jwt = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.authService.login(user);
     <span class="hljs-comment">// E.g., redirect with token as query, or set cookie:</span>
     <span class="hljs-comment">// res.redirect(`http://frontend-app.com?token=${jwt.access_token}`);</span>
     <span class="hljs-keyword">return</span> { access_token: jwt.access_token };
   }
 }
</code></pre>
<ul>
<li><p>The first endpoint (<code>/auth/google</code>) triggers redirect to Google.</p>
</li>
<li><p>The callback endpoint handles the response, then issues your JWT.</p>
</li>
</ul>
</li>
<li><p><strong>Session vs. Stateless</strong></p>
<ul>
<li><p>Many examples use sessions and <code>@nestjs/passport</code> session support, but for APIs you often skip sessions: Passport still invokes <code>validate</code>, returns user, and you issue JWT immediately.</p>
</li>
<li><p>Ensure you disable sessions in <code>PassportModule</code> registration: <code>PassportModule.register({ session: false })</code>.</p>
</li>
</ul>
</li>
<li><p><strong>Multiple Providers</strong></p>
<ul>
<li><p>Repeat strategy setup for each provider (for example, GitHubStrategy).</p>
</li>
<li><p>In <code>validateOAuthLogin</code>, handle <code>provider</code> parameter to distinguish logic.</p>
</li>
<li><p>You can store in your user entity fields like <code>googleId</code>, <code>githubId</code>, and so on, or a separate table for OAuth accounts.</p>
</li>
</ul>
</li>
<li><p><strong>Protecting routes post-login</strong></p>
<ul>
<li><p>Clients use the issued JWT in <code>Authorization: Bearer &lt;token&gt;</code> to access protected endpoints via <code>JwtAuthGuard</code>.</p>
</li>
<li><p>If you prefer sessions/cookies, configure Nest to use sessions and Passport's session features, but for SPAs or mobile clients JWT is common.</p>
</li>
</ul>
</li>
<li><p><strong>Frontend considerations</strong></p>
<ul>
<li><p>Redirect URIs must match those configured in the OAuth provider console.</p>
</li>
<li><p>After receiving JWT, store it securely (for example, HTTP-only cookie or secure storage on client).</p>
</li>
<li><p>Handle token expiry: possibly combine OAuth refresh tokens or your own refresh token flow.</p>
</li>
</ul>
</li>
</ol>
<p>With JWT and OAuth2 strategies set up, your NestJS backend can support secured endpoints, user registration/login flows, and social logins.</p>
<h2 id="heading-conclusion-amp-further-resources">Conclusion &amp; Further Resources</h2>
<h3 id="heading-summary">Summary</h3>
<p>We’ve walked through key aspects of building a NestJS application: its architectural patterns, core building blocks (modules, controllers, providers), dependency injection, routing and middleware, request lifecycle with pipes, guards, exception filters, interceptors, database integration options (TypeORM, Mongoose, Prisma), configuration management, authentication strategies (JWT, OAuth2), and strategies for migrating existing apps.</p>
<p>NestJS provides a structured, TypeScript-first framework that accelerates development of scalable, maintainable backends. By leveraging its module system and built-in integrations, you get consistency, testability, and clear separation of concerns out of the box.</p>
<p>Whether you choose a relational database via TypeORM, a document store with Mongoose, or Prisma’s type-safe client, you can plug these into Nest’s DI container and configuration module. Authentication flows – both JWT-based and social login – fit naturally into Nest’s Passport integration.</p>
<p>Overall, NestJS is well-suited for APIs, microservices, real-time apps, and enterprise backends where maintainability and developer experience matter.</p>
<h3 id="heading-official-docs-and-community-links">Official Docs and Community Links</h3>
<ul>
<li><p><strong>NestJS Official Documentation</strong>: Comprehensive guide and API reference for all core features.</p>
<ul>
<li>https://docs.nestjs.com</li>
</ul>
</li>
<li><p><strong>GitHub Repository</strong>: Source code, issue tracker, and community contributions.</p>
<ul>
<li><a target="_blank" href="https://github.com/nestjs/nest">https://github.com/nestjs/nest</a></li>
</ul>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Write Unit Tests and E2E Tests for NestJS Applications ]]>
                </title>
                <description>
                    <![CDATA[ Recently, I have been writing unit tests and E2E tests for a NestJS project. This was my first time writing tests for a backend project, and I found the process different from my experience with frontend testing, making it challenging to begin. After... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/nestjs-unit-testing-e2e-testing-guide/</link>
                <guid isPermaLink="false">67ffc1695667d9e59ef9bc46</guid>
                
                    <category>
                        <![CDATA[ nestjs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ backend ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ E2ETesting ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gordan Tan ]]>
                </dc:creator>
                <pubDate>Wed, 16 Apr 2025 14:40:41 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1744738441654/1bb2b329-d363-46d7-b091-e0e95ad22c9e.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Recently, I have been writing unit tests and E2E tests for a NestJS project. This was my first time writing tests for a backend project, and I found the process different from my experience with frontend testing, making it challenging to begin.</p>
<p>After looking at some examples, I have gained a clearer understanding of how to approach testing. So I wrote an article to record and share my learning to help others who may be facing similar confusion.</p>
<p>In addition, I have put together a demo project with the relevant unit and E2E tests completed, which may be of interest. I’ve <a target="_blank" href="https://github.com/woai3c/nestjs-demo">uploaded the code to Github here</a>.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-difference-between-unit-testing-and-e2e-testing">Difference Between Unit Testing and E2E Testing</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-writing-unit-tests">Writing Unit Tests</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-the-first-test-case">The First Test Case</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-second-test-case">The Second Test Case</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-unit-test-coverage">Unit Test Coverage</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-writing-e2e-tests">Writing E2E Tests</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-whether-to-write-tests">Whether to Write Tests</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-enhancing-system-robustness">Enhancing System Robustness</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-enhancing-maintainability">Enhancing Maintainability</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-enhancing-development-efficiency">Enhancing Development Efficiency</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-when-not-to-write-tests">When Not to Write Tests?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-reference-materials">Reference Materials</a></p>
</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before diving into this tutorial, you should have:</p>
<ul>
<li><p>Basic knowledge of TypeScript and Node.js</p>
</li>
<li><p>Familiarity with NestJS fundamentals</p>
</li>
<li><p>Understanding of RESTful APIs</p>
</li>
<li><p>MongoDB installed (as the example uses MongoDB)</p>
</li>
<li><p>Node.js and npm/yarn installed on your system</p>
</li>
<li><p>Basic understanding of testing concepts</p>
</li>
</ul>
<p>You can find the complete code examples in the <a target="_blank" href="https://github.com/woai3c/nestjs-demo">demo repository</a>. You can clone it to follow along with the examples.</p>
<h2 id="heading-difference-between-unit-testing-and-e2e-testing">Difference Between Unit Testing and E2E Testing</h2>
<p>Unit tests and E2E tests are methods of software testing, but they have different goals and scopes.</p>
<p>Unit testing involves checking and verifying the smallest testable unit within the software. A function or a method, for example, can be considered a unit. In unit testing, you provide expected outputs for various inputs of a function and validate the correctness of its operation. The goal of unit testing is to quickly identify bugs within the function, and they are easy to write and execute rapidly.</p>
<p>On the other hand, E2E tests often simulate real-world user scenarios to test the entire application. For instance, the frontend typically uses a browser or headless browser for testing, while the backend does so by simulating API calls.</p>
<p>Within a NestJS project, unit tests might assess a specific service or a method of a controller, such as verifying if the <code>update</code> method in the Users module correctly updates a user. An E2E test, however, may examine a complete user journey, from creating a new user to updating their password and eventually deleting the user, which involves multiple services and controllers.</p>
<h2 id="heading-how-to-write-unit-tests">How to Write Unit Tests</h2>
<p>Writing unit tests for a utility function or method that doesn't involve interfaces is relatively straightforward. You only need to consider the various inputs and write the corresponding test code. But the situation becomes more complex once interfaces come into play. Let's use code as an example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> validateUser(
  username: <span class="hljs-built_in">string</span>,
  password: <span class="hljs-built_in">string</span>,
): <span class="hljs-built_in">Promise</span>&lt;UserAccountDto&gt; {
  <span class="hljs-keyword">const</span> entity = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.usersService.findOne({ username });
  <span class="hljs-keyword">if</span> (!entity) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnauthorizedException(<span class="hljs-string">'User not found'</span>);
  }
  <span class="hljs-keyword">if</span> (entity.lockUntil &amp;&amp; entity.lockUntil &gt; <span class="hljs-built_in">Date</span>.now()) {
    <span class="hljs-keyword">const</span> diffInSeconds = <span class="hljs-built_in">Math</span>.round((entity.lockUntil - <span class="hljs-built_in">Date</span>.now()) / <span class="hljs-number">1000</span>);
    <span class="hljs-keyword">let</span> message = <span class="hljs-string">`The account is locked. Please try again in <span class="hljs-subst">${diffInSeconds}</span> seconds.`</span>;
    <span class="hljs-keyword">if</span> (diffInSeconds &gt; <span class="hljs-number">60</span>) {
      <span class="hljs-keyword">const</span> diffInMinutes = <span class="hljs-built_in">Math</span>.round(diffInSeconds / <span class="hljs-number">60</span>);
      message = <span class="hljs-string">`The account is locked. Please try again in <span class="hljs-subst">${diffInMinutes}</span> minutes.`</span>;
    }
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnauthorizedException(message);
  }
  <span class="hljs-keyword">const</span> passwordMatch = bcrypt.compareSync(password, entity.password);
  <span class="hljs-keyword">if</span> (!passwordMatch) {
    <span class="hljs-comment">// $inc update to increase failedLoginAttempts</span>
    <span class="hljs-keyword">const</span> update = {
      $inc: { failedLoginAttempts: <span class="hljs-number">1</span> },
    };
    <span class="hljs-comment">// lock account when the third try is failed</span>
    <span class="hljs-keyword">if</span> (entity.failedLoginAttempts + <span class="hljs-number">1</span> &gt;= <span class="hljs-number">3</span>) {
      <span class="hljs-comment">// $set update to lock the account for 5 minutes</span>
      update[<span class="hljs-string">'$set'</span>] = { lockUntil: <span class="hljs-built_in">Date</span>.now() + <span class="hljs-number">5</span> * <span class="hljs-number">60</span> * <span class="hljs-number">1000</span> };
    }
    <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.usersService.update(entity._id, update);
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnauthorizedException(<span class="hljs-string">'Invalid password'</span>);
  }
  <span class="hljs-comment">// if validation is sucessful, then reset failedLoginAttempts and lockUntil</span>
  <span class="hljs-keyword">if</span> (
    entity.failedLoginAttempts &gt; <span class="hljs-number">0</span> ||
    (entity.lockUntil &amp;&amp; entity.lockUntil &gt; <span class="hljs-built_in">Date</span>.now())
  ) {
    <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.usersService.update(entity._id, {
      $set: { failedLoginAttempts: <span class="hljs-number">0</span>, lockUntil: <span class="hljs-literal">null</span> },
    });
  }
  <span class="hljs-keyword">return</span> { userId: entity._id, username } <span class="hljs-keyword">as</span> UserAccountDto;
}
</code></pre>
<p>The code above is a method <code>validateUser</code> in the <code>auth.service.ts</code> file, primarily used to verify whether the username and password entered by the user during login are correct. It contains the following logic:</p>
<ol>
<li><p>Check if the user exists based on <code>username</code>. If not, throw a 401 exception (a 404 exception is also feasible).</p>
</li>
<li><p>See if the user is locked out. If so, throw a 401 exception with a relevant message.</p>
</li>
<li><p>Encrypt the <code>password</code> and compare it with the password in the database. If it's incorrect, throw a 401 exception (three consecutive failed login attempts will lock the account for 5 minutes).</p>
</li>
<li><p>If the login is successful, clear any previously failed login attempt counts (if applicable) and return the user <code>id</code> and <code>username</code> to the next stage.</p>
</li>
</ol>
<p>As you can see, the <code>validateUser</code> method includes four processing logics. So we need to write corresponding unit test code for these four points to ensure that the entire <code>validateUser</code> function is operating correctly.</p>
<h3 id="heading-the-first-test-case">The First Test Case</h3>
<p>When we start writing unit tests, we encounter a problem: the <code>findOne</code> method needs to interact with the database, and it looks for corresponding users in the database through <code>username</code>. But if every unit test has to interact with the database, the testing will become very cumbersome. So we can mock fake data to achieve this.</p>
<p>For example, assume we have registered a user named <code>woai3c</code>. Then, during login, the user data can be retrieved in the <code>validateUser</code> method through <code>const entity = await this.usersService.findOne({ username });</code>. As long as this line of code can return the desired data, there is no problem, even without database interaction. We can achieve this through mock data.</p>
<p>Now, let's look at the relevant test code for the <code>validateUser</code> method:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Test } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/testing'</span>;
<span class="hljs-keyword">import</span> { AuthService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/modules/auth/auth.service'</span>;
<span class="hljs-keyword">import</span> { UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/modules/users/users.service'</span>;
<span class="hljs-keyword">import</span> { UnauthorizedException } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { TEST_USER_NAME, TEST_USER_PASSWORD } <span class="hljs-keyword">from</span> <span class="hljs-string">'@tests/constants'</span>;
describe(<span class="hljs-string">'AuthService'</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">let</span> authService: AuthService; <span class="hljs-comment">// Use the actual AuthService type</span>
  <span class="hljs-keyword">let</span> usersService: Partial&lt;Record&lt;keyof UsersService, jest.Mock&gt;&gt;;
  beforeEach(<span class="hljs-keyword">async</span> () =&gt; {
    usersService = {
      findOne: jest.fn(),
    };
    <span class="hljs-keyword">const</span> <span class="hljs-keyword">module</span> = await Test.createTestingModule({
      providers: [        AuthService,
        {
          provide: UsersService,
          useValue: usersService,
        },
      ],
    }).compile();
    authService = <span class="hljs-built_in">module</span>.get&lt;AuthService&gt;(AuthService);
  });
  describe(<span class="hljs-string">'validateUser'</span>, <span class="hljs-function">() =&gt;</span> {
    it(<span class="hljs-string">'should throw an UnauthorizedException if user is not found'</span>, <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">await</span> expect(
        authService.validateUser(TEST_USER_NAME, TEST_USER_PASSWORD),
      ).rejects.toThrow(UnauthorizedException);
    });
    <span class="hljs-comment">// other tests...</span>
  });
});
</code></pre>
<p>We get the user data by calling the <code>findOne</code> method of <code>usersService</code>, so we need to mock the <code>findOne</code> method of <code>usersService</code> in the test code:</p>
<pre><code class="lang-typescript">beforeEach(<span class="hljs-keyword">async</span> () =&gt; {
    usersService = {
      findOne: jest.fn(), <span class="hljs-comment">// mock findOne method</span>
    };
    <span class="hljs-keyword">const</span> <span class="hljs-keyword">module</span> = await Test.createTestingModule({
      providers: [        AuthService, <span class="hljs-comment">// real AuthService, because we are testing its methods</span>
        {
          provide: UsersService, <span class="hljs-comment">// use mock usersService instead of real usersService</span>
          useValue: usersService,
        },
      ],
    }).compile();
    authService = <span class="hljs-built_in">module</span>.get&lt;AuthService&gt;(AuthService);
  });
</code></pre>
<p>We use <code>jest.fn()</code> to return a function to replace the real <code>usersService.findOne()</code>. If <code>usersService.findOne()</code> is called now, there will be no return value, so the first unit test case will pass:</p>
<pre><code class="lang-typescript">it(<span class="hljs-string">'should throw an UnauthorizedException if user is not found'</span>, <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">await</span> expect(
    authService.validateUser(TEST_USER_NAME, TEST_USER_PASSWORD),
  ).rejects.toThrow(UnauthorizedException);
});
</code></pre>
<p>Since <code>findOne</code> in <code>const entity = await this.usersService.findOne({ username });</code> of the <code>validateUser</code> method is a mocked fake function with no return value, the 2nd to 4th lines of code in the <code>validateUser</code> method could execute:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">if</span> (!entity) {
  <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnauthorizedException(<span class="hljs-string">'User not found'</span>);
}
</code></pre>
<p>It throws a 401 error, which is as expected.</p>
<h3 id="heading-the-second-test-case">The Second Test Case</h3>
<p>The second logic in the <code>validateUser</code> method is to determine if the user is locked, with the corresponding code as follows:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">if</span> (entity.lockUntil &amp;&amp; entity.lockUntil &gt; <span class="hljs-built_in">Date</span>.now()) {
  <span class="hljs-keyword">const</span> diffInSeconds = <span class="hljs-built_in">Math</span>.round((entity.lockUntil - <span class="hljs-built_in">Date</span>.now()) / <span class="hljs-number">1000</span>);
  <span class="hljs-keyword">let</span> message = <span class="hljs-string">`The account is locked. Please try again in <span class="hljs-subst">${diffInSeconds}</span> seconds.`</span>;
  <span class="hljs-keyword">if</span> (diffInSeconds &gt; <span class="hljs-number">60</span>) {
    <span class="hljs-keyword">const</span> diffInMinutes = <span class="hljs-built_in">Math</span>.round(diffInSeconds / <span class="hljs-number">60</span>);
    message = <span class="hljs-string">`The account is locked. Please try again in <span class="hljs-subst">${diffInMinutes}</span> minutes.`</span>;
  }
  <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnauthorizedException(message);
}
</code></pre>
<p>As you can see, we can determine that the current account is locked if there is a lock time <code>lockUntil</code> in the user data and the lock end time is greater than the current time. So we need to mock a user data with the <code>lockUntil</code> field:</p>
<pre><code class="lang-typescript">it(<span class="hljs-string">'should throw an UnauthorizedException if the account is locked'</span>, <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> lockedUser = {
    _id: TEST_USER_ID,
    username: TEST_USER_NAME,
    password: TEST_USER_PASSWORD,
    lockUntil: <span class="hljs-built_in">Date</span>.now() + <span class="hljs-number">1000</span> * <span class="hljs-number">60</span> * <span class="hljs-number">5</span>, <span class="hljs-comment">// The account is locked for 5 minutes</span>
  };
  usersService.findOne.mockResolvedValueOnce(lockedUser);
  <span class="hljs-keyword">await</span> expect(
    authService.validateUser(TEST_USER_NAME, TEST_USER_PASSWORD),
  ).rejects.toThrow(UnauthorizedException);
});
</code></pre>
<p>In the test code above, an object <code>lockedUser</code> is first defined, which contains the <code>lockUntil</code> field we need. Then, it is used as the return value for <code>findOne</code>, achieved by <code>usersService.findOne.mockResolvedValueOnce(lockedUser);</code>. Thus, when the <code>validateUser</code> method is executed, the user data within it is the mocked data, successfully allowing the second test case to pass.</p>
<h3 id="heading-unit-test-coverage">Unit Test Coverage</h3>
<p>Unit test coverage (Code Coverage) is a metric used to describe how much of the application code has been covered or tested by unit tests. It is typically expressed as a percentage, indicating how much of all possible code paths have been covered by test cases.</p>
<p>Unit test coverage usually includes the following types:</p>
<ul>
<li><p>Line Coverage: How many lines of code are covered by the tests.</p>
</li>
<li><p>Function Coverage: How many functions or methods are covered by the tests.</p>
</li>
<li><p>Branch Coverage: How many code branches are covered by the tests (for example, <code>if/else</code> statements).</p>
</li>
<li><p>Statement Coverage: How many statements in the code are covered by the tests.</p>
</li>
</ul>
<p>Unit test coverage is an important metric to measure the quality of unit tests, but it is not the only metric. A high coverage rate can help to detect errors in the code, but it does not guarantee the quality of the code. A low coverage rate may mean that there is untested code, potentially with undetected errors.</p>
<p>The image below shows the unit test coverage results for a demo project:</p>
<p><a target="_blank" href="https://camo.githubusercontent.com/e3de4ecc6be093ac92a514fa183f688c455b00cc15a3d003bfe2f25e31a08c4f/68747470733a2f2f6d69726f2e6d656469756d2e636f6d2f76322f726573697a653a6669743a313331302f666f726d61743a776562702f302a515a5f4d4a77774c715752314d3136652e706e67"><img src="https://camo.githubusercontent.com/e3de4ecc6be093ac92a514fa183f688c455b00cc15a3d003bfe2f25e31a08c4f/68747470733a2f2f6d69726f2e6d656469756d2e636f6d2f76322f726573697a653a6669743a313331302f666f726d61743a776562702f302a515a5f4d4a77774c715752314d3136652e706e67" alt="Unit test coverage overview showing test results with percentages for statements, branches, functions, and lines" width="600" height="400" loading="lazy"></a></p>
<p>For files like services and controllers, it's generally better to have a higher unit test coverage, while for files like modules there's no need to write unit tests – nor is it possible to write them, as it's meaningless.</p>
<p>This is because NestJS modules are primarily configuration files that define the structure of your application by connecting controllers, services, and other components together. They don't contain actual business logic to test, but rather serve as wiring instructions for the dependency injection system. Testing modules would only verify that NestJS's core functionality works correctly, which is already tested by the NestJS team themselves.</p>
<p>The above image represents the overall metrics for the entire unit test coverage. If you want to view the test coverage for a specific function, you can open the <code>coverage/lcov-report/index.html</code> file in the project's root directory. For example, I want to see the specific test situation for the <code>validateUser</code> method:</p>
<p><a target="_blank" href="https://camo.githubusercontent.com/e5757001ae5bfec61c2b3ed19f7ef99cffc6c014480d7dad17ab28a2713f6aa0/68747470733a2f2f6d69726f2e6d656469756d2e636f6d2f76322f726573697a653a6669743a313430302f666f726d61743a776562702f302a4e32542d44694d754566776b332d33322e706e67"><img src="https://camo.githubusercontent.com/e5757001ae5bfec61c2b3ed19f7ef99cffc6c014480d7dad17ab28a2713f6aa0/68747470733a2f2f6d69726f2e6d656469756d2e636f6d2f76322f726573697a653a6669743a313430302f666f726d61743a776562702f302a4e32542d44694d754566776b332d33322e706e67" alt="Detailed test coverage for the validateUser method showing specific uncovered lines highlighted in red" width="600" height="400" loading="lazy"></a></p>
<p>As you can see, the original unit test coverage for the <code>validateUser</code> method is not 100%, and there are still two lines of code that were not executed. But it doesn't matter much, as it does not affect the four key processing nodes, and we shouldn’t pursue high test coverage unidimensionally.</p>
<h2 id="heading-how-to-write-e2e-tests">How to Write E2E Tests</h2>
<p>In the unit tests section, you learned how to write unit tests for each feature of the <code>validateUser()</code> function, using mocked data to ensure that each feature could be tested.</p>
<p>In e2E testing, we need to simulate real user scenarios, so connecting to a database for testing is necessary. So, the methods in the <code>auth.service.ts</code> module that we'll be testing all interact with the database.</p>
<p>The <code>auth</code> module primarily includes the following features:</p>
<ul>
<li><p>Registration</p>
</li>
<li><p>Login</p>
</li>
<li><p>Token refresh</p>
</li>
<li><p>Reading user information</p>
</li>
<li><p>Changing password</p>
</li>
<li><p>Deleting users</p>
</li>
</ul>
<p>E2E tests need to test these six features one by one, starting with <code>registration</code> and ending with <code>deleting users</code>. During testing, we can create a dedicated test user to conduct the tests and then delete this test user upon completion, so we don’t leave any unnecessary information in the test database.</p>
<pre><code class="lang-typescript">beforeAll(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> moduleFixture: TestingModule = <span class="hljs-keyword">await</span> Test.createTestingModule({
    imports: [AppModule],
  }).compile()
  app = moduleFixture.createNestApplication()
  <span class="hljs-keyword">await</span> app.init()
  <span class="hljs-comment">// Perform a login to obtain a token</span>
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request(app.getHttpServer())
    .post(<span class="hljs-string">'/auth/register'</span>)
    .send({ username: TEST_USER_NAME, password: TEST_USER_PASSWORD })
    .expect(<span class="hljs-number">201</span>)
  accessToken = response.body.access_token
  refreshToken = response.body.refresh_token
})
afterAll(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">await</span> request(app.getHttpServer())
    .delete(<span class="hljs-string">'/auth/delete-user'</span>)
    .set(<span class="hljs-string">'Authorization'</span>, <span class="hljs-string">`Bearer <span class="hljs-subst">${accessToken}</span>`</span>)
    .expect(<span class="hljs-number">200</span>)
  <span class="hljs-keyword">await</span> app.close()
})
</code></pre>
<p>The <code>beforeAll</code> hook function runs before all tests begin, so we can register a test account <code>TEST_USER_NAME</code> here. The <code>afterAll</code> hook function runs after all tests end, so it's suitable to delete the test account <code>TEST_USER_NAME</code> here. It also conveniently tests the registration and deletion functions.</p>
<p>In the previous section's unit tests, we wrote relevant unit tests around the <code>validateUser</code> method. Actually, this method is executed during login to validate if the user's account and password are correct. So this E2E test will also use the login process to demonstrate how to compose the E2E test cases.</p>
<p>The entire login test process includes five small tests:</p>
<pre><code class="lang-typescript">describe(<span class="hljs-string">'login'</span>, <span class="hljs-function">() =&gt;</span> {
    it(<span class="hljs-string">'/auth/login (POST)'</span>, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-comment">// ...</span>
    })
    it(<span class="hljs-string">'/auth/login (POST) with user not found'</span>, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-comment">// ...</span>
    })
    it(<span class="hljs-string">'/auth/login (POST) without username or password'</span>, <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-comment">// ...</span>
    })
    it(<span class="hljs-string">'/auth/login (POST) with invalid password'</span>, <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-comment">// ...</span>
    })
    it(<span class="hljs-string">'/auth/login (POST) account lock after multiple failed attempts'</span>, <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-comment">// ...</span>
    })
  })
</code></pre>
<p>These five tests are as follows:</p>
<ol>
<li><p>Successful login, return 200</p>
</li>
<li><p>If the user does not exist, throw a 401 exception</p>
</li>
<li><p>If password or username is not provided, throw a 400 exception</p>
</li>
<li><p>Login with the wrong password, throw a 401 exception</p>
</li>
<li><p>If the account is locked, throw a 401 exception</p>
</li>
</ol>
<p>Now let's start writing the E2E tests:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// login success</span>
it(<span class="hljs-string">'/auth/login (POST)'</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> request(app.getHttpServer())
    .post(<span class="hljs-string">'/auth/login'</span>)
    .send({ username: TEST_USER_NAME, password: TEST_USER_PASSWORD })
    .expect(<span class="hljs-number">200</span>)
})
<span class="hljs-comment">// if user not found, should throw 401 exception</span>
it(<span class="hljs-string">'/auth/login (POST) with user not found'</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> request(app.getHttpServer())
    .post(<span class="hljs-string">'/auth/login'</span>)
    .send({ username: TEST_USER_NAME2, password: TEST_USER_PASSWORD })
    .expect(<span class="hljs-number">401</span>) <span class="hljs-comment">// Expect an unauthorized error</span>
})
</code></pre>
<p>Writing E2E test code is relatively straightforward: you simply call the interface and then verify the result. For example, for the successful login test, we just need to verify that the returned result is 200.</p>
<p>The first four tests are quite simple. Now let's look at a slightly more complicated E2E test, which is to verify whether an account is locked.</p>
<pre><code class="lang-typescript">it(<span class="hljs-string">'/auth/login (POST) account lock after multiple failed attempts'</span>, <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> moduleFixture: TestingModule = <span class="hljs-keyword">await</span> Test.createTestingModule({
    imports: [AppModule],
  }).compile()
  <span class="hljs-keyword">const</span> app = moduleFixture.createNestApplication()
  <span class="hljs-keyword">await</span> app.init()
  <span class="hljs-keyword">const</span> registerResponse = <span class="hljs-keyword">await</span> request(app.getHttpServer())
    .post(<span class="hljs-string">'/auth/register'</span>)
    .send({ username: TEST_USER_NAME2, password: TEST_USER_PASSWORD })
  <span class="hljs-keyword">const</span> accessToken = registerResponse.body.access_token
  <span class="hljs-keyword">const</span> maxLoginAttempts = <span class="hljs-number">3</span> <span class="hljs-comment">// lock user when the third try is failed</span>
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; maxLoginAttempts; i++) {
    <span class="hljs-keyword">await</span> request(app.getHttpServer())
      .post(<span class="hljs-string">'/auth/login'</span>)
      .send({ username: TEST_USER_NAME2, password: <span class="hljs-string">'InvalidPassword'</span> })
  }
  <span class="hljs-comment">// The account is locked after the third failed login attempt</span>
  <span class="hljs-keyword">await</span> request(app.getHttpServer())
    .post(<span class="hljs-string">'/auth/login'</span>)
    .send({ username: TEST_USER_NAME2, password: TEST_USER_PASSWORD })
    .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> {
      expect(res.body.message).toContain(
        <span class="hljs-string">'The account is locked. Please try again in 5 minutes.'</span>,
      )
    })
  <span class="hljs-keyword">await</span> request(app.getHttpServer())
    .delete(<span class="hljs-string">'/auth/delete-user'</span>)
    .set(<span class="hljs-string">'Authorization'</span>, <span class="hljs-string">`Bearer <span class="hljs-subst">${accessToken}</span>`</span>)
  <span class="hljs-keyword">await</span> app.close()
})
</code></pre>
<p>When a user fails to log in three times in a row, the account will be locked. So in this test, we cannot use the test account <code>TEST_USER_NAME</code>, because if the test is successful, this account will be locked and unable to continue the following tests. We need to register another new user <code>TEST_USER_NAME2</code> specifically to test account locking, and delete this user after the test is successful.</p>
<p>So, as you can see, the code for this E2E test is quite substantial, requiring a lot of setup and teardown work, but the actual test code is just these few lines:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// login three times</span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; maxLoginAttempts; i++) {
  <span class="hljs-keyword">await</span> request(app.getHttpServer())
    .post(<span class="hljs-string">'/auth/login'</span>)
    .send({ username: TEST_USER_NAME2, password: <span class="hljs-string">'InvalidPassword'</span> })
}
<span class="hljs-comment">// test if the account is locked</span>
<span class="hljs-keyword">await</span> request(app.getHttpServer())
  .post(<span class="hljs-string">'/auth/login'</span>)
  .send({ username: TEST_USER_NAME2, password: TEST_USER_PASSWORD })
  .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> {
    expect(res.body.message).toContain(
      <span class="hljs-string">'The account is locked. Please try again in 5 minutes.'</span>,
    )
  })
</code></pre>
<p>Writing E2E test code is relatively simple. You don't need to consider mock data or test coverage. It's sufficient if the entire system process runs as expected.</p>
<h2 id="heading-when-to-write-tests">When to Write Tests</h2>
<p>If possible, I generally recommend writing tests. Doing so can enhance the robustness, maintainability, and development efficiency of the system. Here are some key reasons why writing tests is useful:</p>
<h3 id="heading-enhancing-system-robustness">Enhancing System Robustness</h3>
<p>When writing code, you usually focus on the program flow under normal inputs to ensure the core functionality works properly. But you might often overlook some edge cases, such as abnormal inputs.</p>
<p>Writing tests changes this, as it forces you to consider how to handle these cases and respond appropriately, thus preventing crashes. So we can say that writing tests indirectly improves system robustness.</p>
<h3 id="heading-enhancing-maintainability">Enhancing Maintainability</h3>
<p>Taking over a new project that includes comprehensive tests can be very pleasant. They act as a guide, helping you quickly understand the various functionalities. Just by looking at the test code, you can easily grasp the expected behavior and boundary conditions of each function without having to go through each line of the function's code.</p>
<h3 id="heading-enhancing-development-efficiency">Enhancing Development Efficiency</h3>
<p>Imagine a project that hasn't been updated for a while suddenly receives new requirements. After making changes, you might worry about introducing bugs. Without tests, you would need to manually test the entire project again — wasting time and being inefficient.</p>
<p>With complete tests, a single command can tell you whether the code changes have impacted existing functionalities. Even if there are errors, you can quickly locate them and address them.</p>
<h2 id="heading-when-not-to-write-tests">When Not to Write Tests</h2>
<p>For short-term projects and projects with very fast requirement iterations, it's not recommended to write tests.</p>
<p>For example, a project built for an event that will be useless after the event ends doesn't need tests. Also, for projects that undergo very fast requirement iterations, writing tests could enhance development efficiency, but that's based on the premise that function iterations are slow. If the function you just completed changes in a day or two, the related test code must be rewritten.</p>
<p>So, it's better not to write tests at all in these cases and rely on the testing team instead – because writing tests is very time-consuming and not worth the effort for these situations.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>I’ve explained in detail how to write unit tests and E2E tests for NestJS projects. But I still want to reiterate the importance of testing. It can enhance the robustness, maintainability, and development efficiency of the system.</p>
<p>If you don't have the opportunity to write tests, I suggest you start a practice project yourself or participate in some open-source projects and contribute code to them. Open-source projects generally have stricter code requirements. Contributing code may require you to write new test cases or modify existing ones.</p>
<h3 id="heading-reference-materials">Reference Materials</h3>
<ul>
<li><p><a target="_blank" href="https://nestjs.com/">NestJS</a>: A framework for building efficient, scalable Node.js server-side applications.</p>
</li>
<li><p><a target="_blank" href="https://www.mongodb.com/">MongoDB</a>: A NoSQL database used for data storage.</p>
</li>
<li><p><a target="_blank" href="https://jestjs.io/">Jest</a>: A testing framework for JavaScript and TypeScript.</p>
</li>
<li><p><a target="_blank" href="https://github.com/visionmedia/supertest">Supertest</a>: A library for testing HTTP servers.</p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Create Microservices with NestJS ]]>
                </title>
                <description>
                    <![CDATA[ Microservices architecture has become a popular approach for building scalable and maintainable applications. By breaking down large applications into smaller, independent services, developers can improve performance, maintainability, and scalability... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/create-microservices-with-nestjs/</link>
                <guid isPermaLink="false">67e434766d7e1561ea4bf0e6</guid>
                
                    <category>
                        <![CDATA[ nestjs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Wed, 26 Mar 2025 17:08:06 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1743008871537/ad2be682-1c63-4d10-9cd3-7b33a7451b9b.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Microservices architecture has become a popular approach for building scalable and maintainable applications. By breaking down large applications into smaller, independent services, developers can improve performance, maintainability, and scalability. If you're looking to master microservices with Nest.js, we have the perfect course for you.</p>
<p>We just published a course on the <a target="_blank" href="http://freeCodeCamp.org">freeCodeCamp.org</a> YouTube channel that will teach you how to build microservices using Nest.js. Taught by Hhaider Malik, this course walks you through building a delivery service application that tracks rider activity by saving their coordinates every three hours. You'll develop two microservices—a Login Service and a Rider Service—and enable seamless communication between them. By the end of the course, you'll have the skills to design, develop, and deploy scalable microservices using Nest.js and MongoDB.</p>
<h3 id="heading-what-youll-learn">What You’ll Learn</h3>
<p>This hands-on course covers essential topics for building microservices, including:</p>
<ul>
<li><p><strong>Setting up a Nest.js microservices project</strong> – Learn how to scaffold and structure a Nest.js application for microservices.</p>
</li>
<li><p><strong>Using MongoDB with Docker</strong> – Understand the importance of Docker, run MongoDB in a container, and use Docker Compose for setup.</p>
</li>
<li><p><strong>Schema design and data validation</strong> – Define schemas using Mongoose and validate request bodies to ensure data integrity.</p>
</li>
<li><p><strong>Inter-microservice communication</strong> – Implement TCP-based communication between services and use events for interaction.</p>
</li>
<li><p><strong>Testing and debugging</strong> – Learn how to test microservices and fix common issues to ensure reliability.</p>
</li>
</ul>
<h3 id="heading-why-this-course">Why This Course?</h3>
<p>Nest.js is a powerful framework that simplifies building scalable server-side applications with TypeScript. This course provides practical, real-world experience by guiding you through building and testing a real microservices-based project.</p>
<p>Watch the full course now on <a target="_blank" href="https://youtu.be/t76UMpwFNs0">the freeCodeCamp.org YouTube channel</a> (2-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/t76UMpwFNs0" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Handle File Uploads in NestJS with Multer ]]>
                </title>
                <description>
                    <![CDATA[ Uploading files is an important need in many applications. Using Multer, you can set up a NestJS file upload feature in an easy and straightforward way. In this guide, we’ll walk through the steps to create a resource dedicated to file uploads, ensur... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-handle-file-uploads-in-nestjs-with-multer/</link>
                <guid isPermaLink="false">66ce8e78c48f483101258dbc</guid>
                
                    <category>
                        <![CDATA[ nestjs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Abimbola Adedotun Samuel ]]>
                </dc:creator>
                <pubDate>Wed, 28 Aug 2024 02:42:00 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724695369812/b0511a24-bbb6-4dae-9ccf-b511383b8f6a.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Uploading files is an important need in many applications. Using Multer, you can set up a NestJS file upload feature in an easy and straightforward way.</p>
<p>In this guide, we’ll walk through the steps to create a resource dedicated to file uploads, ensuring that your application can easily manage user files. You'll configure your application to handle files securely and seamlessly.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>This is a hands-on guide. To follow along, you must have the following things:</p>
<ul>
<li><p>Node.js (v14 and above)</p>
</li>
<li><p>Node package manager</p>
</li>
<li><p>Basic understanding of Node.js and NestJS</p>
</li>
<li><p>A code editor, like VS Code</p>
</li>
<li><p>NestJS CLI. You can use the <code>npm install -g @nestjs/cli</code> command to install the CLI.</p>
</li>
</ul>
<h2 id="heading-how-to-set-up-the-project">How to Set up the Project</h2>
<p>Create a new NestJS project:</p>
<pre><code class="lang-bash">$ nest new file-upload-example
</code></pre>
<p>Then navigate to your project directory and run:</p>
<pre><code class="lang-bash">$ <span class="hljs-built_in">cd</span> file-upload-example
</code></pre>
<p>Next, install the <code>multer</code> package—the middleware that will handle your file uploads:</p>
<pre><code class="lang-bash">$ npm install @nestjs/platform-express multer
</code></pre>
<p>Lastly, install the <code>@types/express</code> and <code>@types/multer</code> packages:</p>
<pre><code class="lang-bash">$ npm install -save-dev @types/express @types/multer
</code></pre>
<p>With the project set up and dependencies installed, let’s create the resource for the file upload feature.</p>
<h2 id="heading-how-to-create-a-resource-for-file-upload">How to Create a Resource for File Upload</h2>
<p>Using the NestJS CLI, generate the resource to handle file uploads:</p>
<pre><code class="lang-bash">nest generate resource file-upload
</code></pre>
<p>This command creates a resource <code>file-upload</code> in the <strong>src</strong> directory: module, controller and service, to manage file uploads.</p>
<p><strong>file-upload.module.ts</strong> organizes the file upload logic, <strong>file-upload.controller.ts</strong> handles incoming file upload requests, and <strong>file-upload.service.ts</strong> handles the file upload operations. With the resource created, let’s configure the module, service and controller.</p>
<h2 id="heading-how-to-configure-the-file-upload-resource"><strong>How to Configure the File Upload Resource</strong></h2>
<p>In this section we’ll configure the <strong>file-upload.module.ts</strong>, <strong>file-upload.controller.ts</strong> and <strong>file-upload.service.ts</strong> files.</p>
<p><strong>Module configuration:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { FileUploadService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./file-upload.service'</span>;
<span class="hljs-keyword">import</span> { FileUploadController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./file-upload.controller'</span>;
<span class="hljs-keyword">import</span> { MulterModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/platform-express'</span>;
<span class="hljs-keyword">import</span> { diskStorage } <span class="hljs-keyword">from</span> <span class="hljs-string">'multer'</span>;
@Module({
  <span class="hljs-attr">imports</span>: [
    MulterModule.register({
      <span class="hljs-attr">storage</span>: diskStorage({
        <span class="hljs-attr">destination</span>: <span class="hljs-string">'./uploads'</span>,
        <span class="hljs-attr">filename</span>: <span class="hljs-function">(<span class="hljs-params">req, file, cb</span>) =&gt;</span> {
          <span class="hljs-keyword">const</span> filename = <span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">Date</span>.now()}</span>-<span class="hljs-subst">${file.originalname}</span>`</span>;
          cb(<span class="hljs-literal">null</span>, filename);
        },
      }),
    }),
  ],
  <span class="hljs-attr">controllers</span>: [FileUploadController],
  <span class="hljs-attr">providers</span>: [FileUploadService],
})
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FileUploadModule</span> </span>{}
</code></pre>
<p>Above is the <strong>file-upload.module.ts</strong> file, where we configured the <code>MulterModule</code> to specify the upload destination and how it should name the file.</p>
<p><strong>Controller configuration:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> {
  Controller,
  Post,
  UseInterceptors,
  UploadedFile,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { FileInterceptor } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/platform-express'</span>;
<span class="hljs-keyword">import</span> { FileUploadService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./file-upload.service'</span>;

@Controller(<span class="hljs-string">'file-upload'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FileUploadController</span> </span>{
  <span class="hljs-keyword">constructor</span>(private readonly fileUploadService: FileUploadService) {}

  @Post(<span class="hljs-string">'upload'</span>)
  @UseInterceptors(FileInterceptor(<span class="hljs-string">'file'</span>))
  uploadFile(@UploadedFile() file: Express.Multer.File) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.fileUploadService.handleFileUpload(file);
  }
}
</code></pre>
<p>Is the <strong>file-upload.controller.ts</strong> file above, a <code>POST</code> route is created to handle file uploads. The route listens for file uploads and passes the file to the service for processing</p>
<p><strong>Service configuration:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

@Injectable()
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FileUploadService</span> </span>{
  handleFileUpload(file: Express.Multer.File) {
    <span class="hljs-keyword">return</span> { <span class="hljs-attr">message</span>: <span class="hljs-string">'File uploaded successfully'</span>, <span class="hljs-attr">filePath</span>: file.path };
  }
}
</code></pre>
<p>The service processes the file and returns a response with the file’s path.</p>
<p>Now that the module, service and controller has been configured, we can now add some validation to check the file size and file type.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { BadRequestException, Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

@Injectable()
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FileUploadService</span> </span>{
  handleFileUpload(file: Express.Multer.File) {
    <span class="hljs-keyword">if</span> (!file) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> BadRequestException(<span class="hljs-string">'no file uploaded'</span>);
    }

    <span class="hljs-comment">// validate file type</span>
    <span class="hljs-keyword">const</span> allowedMimeTypes = [<span class="hljs-string">'image/jpeg'</span>, <span class="hljs-string">'image/png'</span>, <span class="hljs-string">'application/pdf'</span>];
    <span class="hljs-keyword">if</span> (!allowedMimeTypes.includes(file.mimetype)) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> BadRequestException(<span class="hljs-string">'invalid file type'</span>);
    }

    <span class="hljs-comment">// validate file size (e.g., max 5mb)</span>
    <span class="hljs-keyword">const</span> maxSize = <span class="hljs-number">5</span> * <span class="hljs-number">1024</span> * <span class="hljs-number">1024</span>;
    <span class="hljs-keyword">if</span> (file.size &gt; maxSize) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> BadRequestException(<span class="hljs-string">'file is too large!'</span>);
    }

    <span class="hljs-keyword">return</span> { <span class="hljs-attr">message</span>: <span class="hljs-string">'File uploaded successfully'</span>, <span class="hljs-attr">filePath</span>: file.path };
  }
}
</code></pre>
<p>We have done the necessary configurations to test the file upload.</p>
<h2 id="heading-how-to-test-the-file-upload"><strong>How to Test the File Upload</strong></h2>
<p>Testing is an important part of building features, in this section we’ll test the file-upload feature using Postman, but you can use any similar tool to test the file upload endpoint. Let’s see our API in action!</p>
<p><strong>Post an image file with the</strong> <code>/file-upload/upload</code> endpoint:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724616574064/c19015a7-5776-4148-838d-dd7acf5c3509.png" alt="postman test for the upload endpoint" class="image--center mx-auto" width="1383" height="842" loading="lazy"></p>
<p>After sending the request, check your response to ensure the file was uploaded successfully. And to further confirm the upload, check the <strong>file-upload-example</strong> and you’ll see the <strong>uploads</strong> directory already created with the file you uploaded.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations to you now that you’ve successfully set up a file upload feature with Multer and NestJS. You configured the module, controller, and service to handle the files securely, and tested the endpoint.</p>
<p>You should understand that these are basic and essential steps to uploading files. You can add to these by building more complex features like handling multiple file uploads, storage in cloud services, and so on.</p>
<p>I really enjoyed working on this demo, and I hope you also find it helpful. For your convenience, the project repository is <a target="_blank" href="https://github.com/dotun2203/nest-js-fileupload-demo">avalilable on Github</a>. You can also connect with me on <a target="_blank" href="https://x.com/Adedot1Abimbola?t=2A7m7RbbIzJei3rrjxsVuA&amp;s=09">Twitter</a>. I’d love to hear from you.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Add JWT-Based Authentication in NestJS ]]>
                </title>
                <description>
                    <![CDATA[ Authentication is a very important aspect of software development. It is the process of verifying a user’s identity. Authentication ensures that only authorized individuals access specific resources or perform certain actions within a system. It prov... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-add-jwt-based-authentication-in-nest-js/</link>
                <guid isPermaLink="false">66c720b8e8452c66efc4c6f7</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JWT ]]>
                    </category>
                
                    <category>
                        <![CDATA[ nestjs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Abimbola Adedotun Samuel ]]>
                </dc:creator>
                <pubDate>Wed, 31 Jul 2024 14:33:47 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/nest-auth-coverimage-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Authentication is a very important aspect of software development. It is the process of verifying a user’s identity.</p>
<p>Authentication ensures that only authorized individuals access specific resources or perform certain actions within a system. It provides accountability by enabling the tracking of user actions and holding individuals responsible for their activities.</p>
<p>It also gives companies data on the number of people using their products. Without proper authentication of your software, you may face security risks. Proper implementation prevents unauthorized access and protects sensitive data. </p>
<p>This tutorial will guide you through building a JWT-based user authentication in NestJS and MongoDb.</p>
<p>NestJS is a powerful Node.js framework for building server-side
applications. MongoDB is popular NoSQL database and we’ll use it to build the basic authentication endpoints.</p>
<p>In this tutorial, we'll cover the following topics:</p>
<ul>
<li>How to creating a new NestJS project and install the necessary dependencies.</li>
<li>How to create user models and schemas.</li>
<li>How to implementing login and signup with JWT token.</li>
<li>How to test the endpoints with postman.</li>
</ul>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<p>This tutorial is a hands-on demo. To follow along, you must have the
following:</p>
<ul>
<li><p><a target="_blank" href="https://nodejs.org/en/download/package-manager"><u>Node.js</u></a> v14
and above</p>
</li>
<li><p>Node package manager</p>
</li>
<li><p><a target="_blank" href="https://www.mongodb.com/docs/compass/current/install/"><u>MongoDB
compass</u></a></p>
</li>
<li><p>Basic understanding of Node.js and preferably ExpressJs</p>
</li>
<li><p>A code editor (for example: VS Code) </p>
</li>
</ul>
<h2 id="heading-how-to-set-up-the-project"><strong>How to Set Up the Project.</strong></h2>
<p>In this section, we’ll set up the project to build our REST API with
NestJS and MongoDB. We’ll start by installing the NestJS CLI and use it to generate new projects.</p>
<p>Install <a target="_blank" href="https://docs.nestjs.com/cli/overview"><u>Nest CLI</u></a>:</p>
<p><code>$ npm i -g @nestjs/cli</code></p>
<p>Then create a new NestJS project with this command:</p>
<p><code>$ nest new project-name</code></p>
<p>Let’s call the project authentication:</p>
<p><code>$ nest new authentication</code></p>
<p>You will see options about which package manager you prefer to install. I
used npm.</p>
<p>After successful installation, move into the created directory and open
the project with your preferred code editor.</p>
<p>Before we go into creating resources and configuring the project, let’s
take a quick look at the <strong>src</strong> directory and its files:</p>
<ul>
<li><p><code>src</code>: The root directory for the source code.</p>
</li>
<li><p><code>src/app.module.ts</code>: The application's main module for configuring and
integrating other modules.</p>
</li>
<li><p><code>src/app.controller.ts</code>: Contains a default controller with a single
route.</p>
</li>
<li><p><code>src/app.service.ts</code>: This includes a basic service using a single
method.</p>
</li>
<li><p><code>src/main.ts</code>: The entry point of the application.</p>
</li>
</ul>
<p>Next, install dependencies to set up and connect the database. You will have to install the <code>mongoose</code> package, <code>bcrypt</code>:</p>
<p><code>$ npm i -save @nestjs/mongoose @types/bcrypt mongoose bcrypt</code></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image3.png" alt="dependencies succefully installed" width="600" height="400" loading="lazy"></p>
<p>Next, set up your database. The <code>MongooseModule</code> from the <code>@nestjs/mongoose</code> dependency will be used to set up the database.</p>
<p>Go to <code>src/app.module.ts</code> file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { AppController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.controller'</span>;
<span class="hljs-keyword">import</span> { AppService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.service'</span>;
<span class="hljs-keyword">import</span> { MongooseModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;
<span class="hljs-keyword">import</span> { UsersModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users/users.module'</span>;
<span class="hljs-keyword">import</span> { AuthModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./auth/auth.module'</span>;
<span class="hljs-keyword">import</span> { ConfigModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/config'</span>;

@Module({
<span class="hljs-attr">imports</span>: [
MongooseModule.forRoot(<span class="hljs-string">'mongodb://localhost:27017/auth-workshop'</span>),
UsersModule,
AuthModule,
ConfigModule.forRoot({
<span class="hljs-attr">envFilePath</span>: <span class="hljs-string">'.env'</span>,
<span class="hljs-attr">isGlobal</span>: <span class="hljs-literal">true</span>,
}),
],
<span class="hljs-attr">controllers</span>: [AppController],
<span class="hljs-attr">providers</span>: [AppService],
})
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppModule</span> </span>{}
</code></pre>
<p>Let's breakdown the code above.
The <code>app.module.ts</code> is the root module of the nestjs application and it is responsible for importing dependecies and other modules required by the application, configuring the application such as database connections and environment variables.</p>
<p>We first specified the <code>app.module.ts</code> file as a module by using the <code>@Module({})</code> decorator:</p>
<pre><code class="lang-js">@Module({})
</code></pre>
<p>The <code>imports</code> array specifies the module that this module depends on. We have the <code>MongooseModule.forRoot('')</code> for database connection using mongoose, <code>ConfigModule.forRoot</code> import sets up the configuration module to read from a <code>.env</code> file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { MongooseModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;
<span class="hljs-keyword">import</span> { UsersModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users/users.module'</span>;
<span class="hljs-keyword">import</span> { AuthModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./auth/auth.module'</span>;
<span class="hljs-keyword">import</span> { ConfigModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/config'</span>;

imports: [
MongooseModule.forRoot(<span class="hljs-string">'mongodb://localhost:27017/auth-workshop'</span>),
UsersModule,
AuthModule,
ConfigModule.forRoot({
<span class="hljs-attr">envFilePath</span>: <span class="hljs-string">'.env'</span>,
<span class="hljs-attr">isGlobal</span>: <span class="hljs-literal">true</span>,
}),
]
</code></pre>
<p>You can replace the <code>MongooseModule.forRoot()</code> URI string with your own database
string.</p>
<p>The <code>controllers</code> array specifies the controller that belongs to this module:</p>
<pre><code class="lang-js">controllers: [AppController]
</code></pre>
<p>The <code>providers</code> array specifies the services that belongs to this module:</p>
<pre><code class="lang-js">providers: [AppService]
</code></pre>
<p>With these configurations, you can start your application by using the
<code>npm run start:dev</code>.</p>
<h2 id="heading-user-models-and-schemas"><strong>User models and schemas</strong></h2>
<p>In this section, we'll define the <code>User</code> model and schema using
<code>mongoose</code>. The <code>User</code> model will represent the users of the application,
and the schema will define the structure of the data stored in MongoDB.
Let’s start by creating a resource module for the users API:</p>
<p>First, create a <code>users</code> resource with the nest CLI:</p>
<p><code>$ nest generate res users</code> </p>
<p>This command will create a new <code>users</code> resource in the <strong>src/users</strong>
directory with a basic structure of controllers and services.</p>
<p>Then define the schema for the <code>Users</code> in <strong>src/users/entities/users.entity.ts</strong>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { Prop, Schema, SchemaFactory }
<span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;
@Schema()
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>{
@Prop()
<span class="hljs-attr">name</span>: string;
@Prop({ <span class="hljs-attr">unique</span>: <span class="hljs-literal">true</span> })
<span class="hljs-attr">email</span>: string;

@Prop()
<span class="hljs-attr">password</span>: string;
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> UserSchema = SchemaFactory.createForClass(User);
</code></pre>
<p>The <code>@Schema</code> decorator is what makes the class a schema. This schema defines three fields for the users: <code>name</code>, <code>email</code>, and <code>password</code>. They are all typed string.</p>
<p>Next, register the schema in the <code>users.module.ts</code> file located in <strong>src/users/users.module.ts</strong>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.service'</span>;
<span class="hljs-keyword">import</span> { UsersController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.controller'</span>;
<span class="hljs-keyword">import</span> { MongooseModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;
<span class="hljs-keyword">import</span> { UserSchema, User } <span class="hljs-keyword">from</span> <span class="hljs-string">'./entities/user.entity'</span>;

@Module({
<span class="hljs-attr">imports</span>: [MongooseModule.forFeature([{ <span class="hljs-attr">name</span>: User.name, <span class="hljs-attr">schema</span>:
UserSchema }])],
<span class="hljs-attr">controllers</span>: [UsersController],
<span class="hljs-attr">providers</span>: [UsersService],
})
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UsersModule</span> </span>{}
</code></pre>
<p>By importing the <code>MongooseModule.forFeature([{}])</code>, this configures mongoose to use the <code>UserSchema</code> for the <code>User</code> model.</p>
<p>By registering the schema with Mongoose, we created a model that's ready to use in our application. This sets the stage for building services and controllers that can interact with our data and handle incoming requests.</p>
<p>Lastly, define the DTO (data transfer object). This object transfers data between systems. It is a simple object that contains only data and has no behaviour.</p>
<p>Create your <code>CreateUserDto</code> in the <strong>src/users/dto/create-user.dto.ts</strong> directory:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CreateUserDto</span> </span>{
<span class="hljs-attr">username</span>: string;
email: string;
password: string;
}
</code></pre>
<h2 id="heading-user-services-and-controllers"><strong>User Services and Controllers</strong></h2>
<p>We have connected to the database and created the schema and model of <code>Users</code>. Let’s write the basic CRUD methods for the users.</p>
<p>Update your <strong>users.service.ts</strong> located in <strong>src/users/users.service.ts</strong>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { Injectable, NotFoundException
} <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { CreateUserDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/create-user.dto'</span>;
<span class="hljs-keyword">import</span> { UpdateUserDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/update-user.dto'</span>;
<span class="hljs-keyword">import</span> { InjectModel } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;
<span class="hljs-keyword">import</span> { User } <span class="hljs-keyword">from</span> <span class="hljs-string">'./entities/user.entity'</span>;
<span class="hljs-keyword">import</span> { Model } <span class="hljs-keyword">from</span> <span class="hljs-string">'mongoose'</span>;

@Injectable()
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UsersService</span> </span>{
<span class="hljs-keyword">constructor</span>(@InjectModel(User.name) private userModel:
Model&amp;lt;User&amp;gt;) {}
<span class="hljs-keyword">async</span> createUsers(createUserDto: CreateUserDto) {
<span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userModel.create(createUserDto);
<span class="hljs-keyword">return</span> user.save();
}
<span class="hljs-keyword">async</span> findAllUsers() {
<span class="hljs-keyword">const</span> users = <span class="hljs-built_in">this</span>.userModel.find();
<span class="hljs-keyword">return</span> users;
}
<span class="hljs-keyword">async</span> findUser(id: number) {
<span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userModel.findById(id);
<span class="hljs-keyword">if</span> (!user) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotFoundException(<span class="hljs-string">'could not find the user'</span>);
<span class="hljs-keyword">return</span> user;
}
updateUser(id: number, <span class="hljs-attr">updateUserDto</span>: UpdateUserDto) {
<span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.userModel.findByIdAndUpdate(id, updateUserDto, { <span class="hljs-attr">new</span>: <span class="hljs-literal">true</span>
});
}
removeUser(id: number) {
<span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.userModel.findByIdAndDelete(id);
};
}
</code></pre>
<p>Update your <strong>users.controller.ts</strong> located in <strong>src/users/users.controller.ts</strong>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { Controller, Get, Post, Body, Patch, Param, Delete, } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.service'</span>;
<span class="hljs-keyword">import</span> { CreateUserDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/create-user.dto'</span>;
<span class="hljs-keyword">import</span> { UpdateUserDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/update-user.dto'</span>;

@Controller(<span class="hljs-string">'users'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UsersController</span> </span>{
<span class="hljs-keyword">constructor</span>(private readonly usersService: UsersService) {}

@Post()
<span class="hljs-keyword">async</span> create(@Body() createUserDto: CreateUserDto) {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.usersService.createUsers(createUserDto);
}

@Get()
<span class="hljs-keyword">async</span> findAll() {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.usersService.findAllUsers();
}

@Get(<span class="hljs-string">':id'</span>)
<span class="hljs-keyword">async</span> findOne(@Param(<span class="hljs-string">'id'</span>) id: string) {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.usersService.findOneUser(+id);
}

@Patch(<span class="hljs-string">':id'</span>)
<span class="hljs-keyword">async</span> update(@Param(<span class="hljs-string">'id'</span>) id: string, @Body() updateUserDto:
UpdateUserDto) {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.usersService.updateUser(+id, updateUserDto);
}

@Delete(<span class="hljs-string">':id'</span>)
<span class="hljs-keyword">async</span> remove(@Param(<span class="hljs-string">'id'</span>) id: string) {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.usersService.removeUser(+id);
}
}
</code></pre>
<p>We created RESTful APIs using <code>mongoose</code>. The methods include:</p>
<ul>
<li><p><code>findAllUsers</code>: Retrieves all user documents from the collection.</p>
</li>
<li><p><code>getUserById</code>: Finds a single user document by ID.</p>
</li>
<li><p><code>createUsers</code>: Adds a new user document to the collection.</p>
</li>
<li><p><code>updateUser</code>: Updates details of existing user in the collection.</p>
</li>
<li><p><code>removeUser</code>: Removes user document by ID.</p>
</li>
</ul>
<h2 id="heading-how-to-implement-sign-up-and-log-in"><strong>How to Implement Sign-up and Log-in</strong></h2>
<p>In this section, we'll create an authentication service that generates JSON Web Tokens (JWTs).</p>
<p>This service will have two methods: <code>signup</code> and <code>login</code>. The <code>signup</code>
method will take a signup request object containing <code>name</code>, <code>email</code>, and
<code>password</code>),and the <code>login</code> method will take a login request object
containing <code>email</code> and <code>password</code>. Both methods will return a JWT. </p>
<p>Let’s start by creating a resource module for the authentication APIs.</p>
<p>Create <code>auth</code> resource with Nest CLI:</p>
<p><code>$ nest generate res auth</code></p>
<p>Then define the DTO for both signup and login. Go to the <strong>dto</strong> folder in the <strong>src/auth/dto</strong> folder:</p>
<p><strong>signup.dto.ts</strong>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SignUpDto</span> </span>{
<span class="hljs-attr">name</span>: string;
email: string;
password: string;
}
</code></pre>
<p><strong>login.dto.ts</strong>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Login</span> </span>{
<span class="hljs-attr">email</span>: string;
password: string;
}
</code></pre>
<p>Next, create a <strong>.env</strong> file in the root directory:</p>
<pre><code class="lang-env">JWT_SECRET=secret
JWT_EXPIRES=3d
</code></pre>
<p>Then add the <code>PassportModule</code>, <code>JwtModule</code> and <code>JwtStrategy</code> to <code>AuthModule</code>. We'll start by installing these packages:</p>
<p><code>$ npm i @nestjs/passport @nestjs/jwt passport passport-jwt bcryptjs</code></p>
<p>Go to <strong>src/auth/auth.module.ts</strong> and import these packages:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { AuthService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./auth.service'</span>;
<span class="hljs-keyword">import</span> { AuthController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./auth.controller'</span>;
<span class="hljs-keyword">import</span> { PassportModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/passport'</span>;
<span class="hljs-keyword">import</span> { JwtModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/jwt'</span>;
<span class="hljs-keyword">import</span> { ConfigModule, ConfigService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/config'</span>;
<span class="hljs-keyword">import</span> { MongooseModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;
<span class="hljs-keyword">import</span> { UserSchema } <span class="hljs-keyword">from</span> <span class="hljs-string">'src/users/entities/user.entity'</span>;


@Module({
<span class="hljs-attr">imports</span>: [
PassportModule.register({ <span class="hljs-attr">defaultStrategy</span>: <span class="hljs-string">'jwt'</span> }),
JwtModule.registerAsync({
<span class="hljs-attr">imports</span>: [ConfigModule],
<span class="hljs-attr">inject</span>: [ConfigService],
<span class="hljs-attr">useFactory</span>: (config: ConfigService) =&amp;gt; {
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">secret</span>: config.get&amp;lt;string&amp;gt;(<span class="hljs-string">'JWT_SECRET'</span>),
<span class="hljs-attr">signOptions</span>: {
<span class="hljs-attr">expiresIn</span>: config.get&amp;lt;string | number&amp;gt;(<span class="hljs-string">'JWT_EXPIRES'</span>),
},
};
},
}),
MongooseModule.forFeature([{ <span class="hljs-attr">name</span>: <span class="hljs-string">'User'</span>, <span class="hljs-attr">schema</span>: UserSchema }]),
],
<span class="hljs-attr">controllers</span>: [AuthController],
<span class="hljs-attr">providers</span>: [AuthService],
})
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthModule</span> </span>{}
</code></pre>
<p>The <code>PassportModule.register</code> configures the Passport module to use the JWT strategy as the authentication mechanism.</p>
<p>The <code>JwtModule.registerAsync</code> configures the JWT module using asynchronous registration process, such a the token expiration time.</p>
<p>The <code>MongooseModule.forFeature()</code> configures mongoose to us the <code>UserSchema</code> for the <code>User</code> model</p>
<p>These imports enable the authentication module to manage user authentication, JWT generation, and database interaction.</p>
<p>Next, create the <code>AuthServices</code> for signup and login in the <strong>src/auth/auth.service.ts</strong> directory:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { Injectable, UnauthorizedException} <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { JwtService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/jwt'</span>;
<span class="hljs-keyword">import</span> { InjectModel } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;
<span class="hljs-keyword">import</span> { Model } <span class="hljs-keyword">from</span> <span class="hljs-string">'mongoose'</span>;
<span class="hljs-keyword">import</span> { User } <span class="hljs-keyword">from</span> <span class="hljs-string">'src/users/entities/user.entity'</span>;
<span class="hljs-keyword">import</span> { SignUpDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/signup.dto'</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> bcrypt <span class="hljs-keyword">from</span> <span class="hljs-string">'bcryptjs'</span>;
<span class="hljs-keyword">import</span> { LoginDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/login.dto'</span>;
<span class="hljs-keyword">import</span> { ConfigService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/config'</span>;

@Injectable()
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthService</span> </span>{
<span class="hljs-keyword">constructor</span>(
@InjectModel(User.name) private userModel: Model&amp;lt;User&amp;gt;,
private jwtService: JwtService,
private configService: ConfigService,
) {}

<span class="hljs-keyword">async</span> signUp(signupDto: SignUpDto) {
<span class="hljs-keyword">const</span> { name, email, password } = signupDto;

<span class="hljs-keyword">const</span> hashedPassword = <span class="hljs-keyword">await</span> bcrypt.hash(password, <span class="hljs-number">10</span>);
<span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userModel.create({
name,
email,
<span class="hljs-attr">password</span>: hashedPassword,
});

<span class="hljs-keyword">await</span> user.save();

<span class="hljs-keyword">const</span> token = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.jwtService.sign(
{ <span class="hljs-attr">id</span>: user.id },
{
<span class="hljs-attr">secret</span>: <span class="hljs-built_in">this</span>.configService.get(<span class="hljs-string">'JWT_SECRET'</span>),
<span class="hljs-attr">expiresIn</span>: <span class="hljs-built_in">this</span>.configService.get(<span class="hljs-string">'JWT_EXPIRES'</span>),
},
);
<span class="hljs-keyword">return</span> { token };
}

<span class="hljs-keyword">async</span> login(loginDto: LoginDto) {
<span class="hljs-keyword">const</span> { email, password } = loginDto;
<span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userModel.findOne({
email,
});

<span class="hljs-keyword">if</span> (!user) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnauthorizedException(<span class="hljs-string">'invalid email or
password'</span>);
<span class="hljs-keyword">const</span> passwordMatch = <span class="hljs-keyword">await</span> bcrypt.compare(password,
user.password);
<span class="hljs-keyword">if</span> (!passwordMatch)
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UnauthorizedException(<span class="hljs-string">'invalid email or password'</span>);
<span class="hljs-keyword">const</span> token = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.jwtService.sign(
{ <span class="hljs-attr">id</span>: user.id },
{
<span class="hljs-attr">secret</span>: <span class="hljs-built_in">this</span>.configService.get(<span class="hljs-string">'JWT_SECRET'</span>),
},
);
<span class="hljs-keyword">return</span> { token };
}
}
</code></pre>
<p>In the <code>AuthService</code>, the <code>signUp</code> method facilitates user registration by:</p>
<ul>
<li>Destructuring the <code>SignupDto</code> object to extract user credentials.</li>
<li>Hashing the password using <code>bcrypt</code> for secure storage.</li>
<li>Creating a new user document in the database via the <code>userModel</code>.</li>
<li>Saving the user document to the database.</li>
<li>Generating a JWT token using <code>jwtService</code> upon successful registration.</li>
<li>Returning the JWT token to the client.</li>
</ul>
<p>The <code>login</code> method authenticates users by:</p>
<ul>
<li>Destructuring the <code>LoginDto</code> object to verify user credentials.</li>
<li>Comparing the input password with the stored hash to ensure a match.</li>
<li>Throwing an <code>UnauthorizedException</code> error if the passwords do not match.</li>
<li>Utilizing the <code>jwtService</code> to sign the user and generate a JWT token upon successful authentication.</li>
<li>Returning the JWT token to the client.</li>
</ul>
<p>Update the <code>AuthController</code> for signup and login in the <strong>src/auth/auth.controller.ts</strong> directory:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { Controller, Post, Body } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { AuthService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./auth.service'</span>;
<span class="hljs-keyword">import</span> { SignUpDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/signup.dto'</span>;
<span class="hljs-keyword">import</span> { LoginDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/login.dto'</span>;

@Controller(<span class="hljs-string">'auth'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthController</span> </span>{
<span class="hljs-keyword">constructor</span>(private readonly authService: AuthService) {}

@Post(<span class="hljs-string">'signup'</span>)
signUp(@Body() signupDto: SignUpDto) {
<span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.authService.signUp(signupDto);
}

@Post(<span class="hljs-string">'login'</span>)
signin(@Body() loginDto: LoginDto) {
<span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.authService.login(loginDto);
}
}
</code></pre>
<p>With these steps, you’ve implemented a basic user login and signup in your application. In the next sections, we’ll test the <code>login</code> and <code>signup</code> routes.</p>
<h2 id="heading-testing-in-postman"><strong>Testing in Postman</strong></h2>
<p>Now that we've set up our endpoints, it's time to put them to the test.
For this example, I'll be using Postman as my API client, but feel free
to use any tool or client that suits your needs. Let's see our API in
action!</p>
<h3 id="heading-how-to-create-a-user-with-the-signup-endpoint"><strong>How to Create a User With the <code>/signup</code> Endpoint:</strong></h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image4-1.png" alt="postman signup test" width="600" height="400" loading="lazy"></p>
<p>After sending a POST request to the /signup endpoint using Postman, we
received a response containing the accessToken. You can verify that a new
user has been successfully created by checking the database.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image1.png" alt="mongodb compass signup verification" width="600" height="400" loading="lazy"></p>
<h3 id="heading-login-as-an-existing-user-with-the-login-endpoint"><strong>Login as an existing user with the <code>/login</code> endpoint:</strong></h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image2-1.png" alt="postman signin test" width="600" height="400" loading="lazy"></p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Congratulations, you've successfully implemented comprehensive
authentication using NestJS, Mongoose, and Passport. We designed a secure
signup and login process, and generated JSON Web Tokens (JWTs).</p>
<p>To further improve and expand your knowledge on authentication, look
into authorization, protecting routes with authentication middleware,
and implementing email verification and password reset functionality.</p>
<p>This foundation provides a solid starting point for building a robust
and scalable authentication system. This project was a pleasure to work
on, and I hope you found it equally enjoyable. </p>
<p>For your convenience, the project <a target="_blank" href="https://github.com/dotun2203/basic-nest-authentication"><u>repository is available on Github</u></a>.</p>
<p>Please don't hesitate to connect with me on Twitter at <a target="_blank" href="https://x.com/Adedot1Abimbola?t=2A7m7RbbIzJei3rrjxsVuA&amp;s=09"><u>@Adedot1Abimbola</u></a>.
I'd love to hear from you</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How To Set Up TypeORM DataSource in Your NestJS Project ]]>
                </title>
                <description>
                    <![CDATA[ Hey there! 👋 Ever since I started working with NestJS, I've been looking for a reliable way to manage my database with TypeORM. Today, I'll share my journey and the steps I took to get it all set up. Alright, before we dive in, let's try to understa... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-setup-typeorm-datasource-nestjs-app/</link>
                <guid isPermaLink="false">66ba5a830013ba5d5012bca1</guid>
                
                    <category>
                        <![CDATA[ nestjs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TypeScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Alaran Ayobami ]]>
                </dc:creator>
                <pubDate>Thu, 25 Apr 2024 11:22:53 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/hq720-1-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hey there! 👋 Ever since I started working with NestJS, I've been looking for a reliable way to manage my database with TypeORM. Today, I'll share my journey and the steps I took to get it all set up.</p>
<p>Alright, before we dive in, let's try to understand what TypeORM and NestJS are.</p>
<h3 id="heading-table-of-contents">Table of contents:</h3>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-typeorm">What is TypeORM?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-nestjs">What is NestJS?</a></li>
<li><a class="post-section-overview" href="#heading-tutorial-prerequisites">Tutorial Prerequisites</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-a-nestjs-project">How to Set Up a NestJS Project</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-typeorm-datasource-for-data-persistency">How to Set Up TypeORM DataSource for Data Persistency</a></li>
<li><a class="post-section-overview" href="#heading-extending-the-datasource-repository-for-custom-methods">Extending The DataSource Repository For Custom Methods</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
<li><a class="post-section-overview" href="#heading-resources">Resources</a></li>
</ul>
<h2 id="heading-what-is-typeorm">What is TypeORM?</h2>
<p>TypeORM is an <a target="_blank" href="https://www.freecodecamp.org/news/what-is-an-orm-the-meaning-of-object-relational-mapping-database-tools/">Object-Relational Mapping (ORM)</a> tool that simplifies working with databases in Node.js and TypeScript applications. It supports various databases like MySQL, PostgreSQL, SQLite, and more, allowing developers to use object-oriented programming concepts instead of dealing with low-level SQL queries. </p>
<p>TypeORM also provides features like schema migrations, query building, and managing relationships between tables.</p>
<h2 id="heading-what-is-nestjs">What is NestJS?</h2>
<p>NestJS is a progressive Node.js framework designed for building efficient, reliable, and scalable server-side applications. It leverages TypeScript's features to enable developers to write structured, maintainable code. </p>
<p>NestJS adopts a modular architecture pattern, allowing you to organize your code into modules, controllers, services, and providers. It provides built-in support for features like dependency injection, middleware, and GraphQL, making it a popular choice for building modern web applications and APIs. </p>
<p>Additionally, NestJS integrates seamlessly with other libraries and frameworks, including TypeORM, to streamline development workflows. Under the hood, it uses a robust HTTP server framework like Express (default) and can be configured to use other Node.js HTTP server frameworks. </p>
<p>Alright, that's a lot, right? Well, before we move on, let's try to break down the phrase, 'NestJS is a progressive Node.js framework,' which simply means that NestJS leverages the latest features of the JavaScript language and server frameworks, thereby providing flexibility for developers to write code in the most suitable language for their projects.<a target="_blank" href="https://docs.nestjs.com/">(Source)</a></p>
<h2 id="heading-tutorial-prerequisites">Tutorial Prerequisites</h2>
<ul>
<li>Node.js. At least version 18</li>
<li>npm. Atleast Version 8</li>
<li>Postgresql. <a target="_blank" href="https://www.postgresql.org/download/">Download Here</a> </li>
<li>Basic familiarity with Typescirpt and Nestjs</li>
<li>Pgadmin 4. <a target="_blank" href="https://www.pgadmin.org/download">Download Here</a></li>
</ul>
<h2 id="heading-how-to-set-up-a-nestjs-project">How to Set Up a NestJS Project</h2>
<p>Run the following commands to install your NestJS project:</p>
<pre><code class="lang-bash">npm i -g @nestjs/cli <span class="hljs-comment"># install nestj cli globally</span>
nest new simple-crm <span class="hljs-comment"># start a new nestjs project</span>
</code></pre>
<p>After installation, run the development server:</p>
<pre><code class="lang-bash">npm run start:dev <span class="hljs-comment"># start the app in watch mode</span>
</code></pre>
<p>Now, let's test our project to see if the <code>nest-cli</code> has properly set up all boiler plate code, by sending a get request to the root URL /</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Screenshot_2024_04_18-1.png" alt="init_test" width="600" height="400" loading="lazy">
_init<em>test</em></p>
<p>Nice! Our project is up and running.</p>
<h3 id="heading-how-to-set-up-typeorm-datasource-for-data-persistency">How to Set Up TypeORM DataSource for Data Persistency</h3>
<pre><code class="lang-bash">npm install --save @nestjs/typeorm typeorm <span class="hljs-comment"># nestjs typeorm drivers</span>
npm install --save pg <span class="hljs-comment"># typeorm postgressql driver</span>
</code></pre>
<p>Let's create the database for the project from Pgadmin 4 interface</p>
<p>Open the Pgadmin 4 interface and right click on the Databases tab to create new database, like so 👇.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Screenshot_2024_04_18-2.png" alt="create_db-1" width="600" height="400" loading="lazy">
_create<em>db-1</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Screenshot_2024_04_18-3.png" alt="create_db-2" width="600" height="400" loading="lazy">
_create<em>db-2</em></p>
<p>Confirm your database has been created successfully.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Screenshot_2024_04_18-4.png" alt="confirm_db" width="600" height="400" loading="lazy">
_confirm<em>db</em></p>
<p>Great, it's time to add the database to our NestJS app using TypeORM.</p>
<p>Create new folder, <strong>datasource</strong> in the <strong>src/</strong> folder of your app, like so 👇</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Screenshot_2024_04_18-5.png" alt="datasource_folder" width="600" height="400" loading="lazy">
_confirm<em>folder</em></p>
<p>Create a  new file <strong>typeorm.module.ts</strong>, in the <strong>datasource</strong> folder, and add the following code:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { DataSource } <span class="hljs-keyword">from</span> <span class="hljs-string">'typeorm'</span>;
<span class="hljs-keyword">import</span> { Global, Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

<span class="hljs-meta">@Global</span>() <span class="hljs-comment">// makes the module available globally for other modules once imported in the app modules</span>
<span class="hljs-meta">@Module</span>({
  imports: [],
  providers: [
    {
      provide: DataSource, <span class="hljs-comment">// add the datasource as a provider</span>
      inject: [],
      useFactory: <span class="hljs-keyword">async</span> () =&gt; {
        <span class="hljs-comment">// using the factory function to create the datasource instance</span>
        <span class="hljs-keyword">try</span> {
          <span class="hljs-keyword">const</span> dataSource = <span class="hljs-keyword">new</span> DataSource({
            <span class="hljs-keyword">type</span>: <span class="hljs-string">'postgres'</span>,
            host: <span class="hljs-string">'localhost'</span>,
            port: <span class="hljs-number">5432</span>,
            username: <span class="hljs-string">'ayo'</span>,
            password: <span class="hljs-string">'haywon'</span>,
            database: <span class="hljs-string">'simple-crm_db'</span>,
            synchronize: <span class="hljs-literal">true</span>,
            entities: [<span class="hljs-string">`<span class="hljs-subst">${__dirname}</span>/../**/**.entity{.ts,.js}`</span>], <span class="hljs-comment">// this will automatically load all entity file in the src folder</span>
          });
          <span class="hljs-keyword">await</span> dataSource.initialize(); <span class="hljs-comment">// initialize the data source</span>
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Database connected successfully'</span>);
          <span class="hljs-keyword">return</span> dataSource;
        } <span class="hljs-keyword">catch</span> (error) {
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Error connecting to database'</span>);
          <span class="hljs-keyword">throw</span> error;
        }
      },
    },
  ],
  <span class="hljs-built_in">exports</span>: [DataSource],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> TypeOrmModule {}
</code></pre>
<p>Add the TypeORM module to the App module imports array, like so 👇</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { AppController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.controller'</span>;
<span class="hljs-keyword">import</span> { AppService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.service'</span>;
<span class="hljs-keyword">import</span> { TypeOrmModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./datasource/typeorm.module'</span>;

<span class="hljs-meta">@Module</span>({
  imports: [TypeOrmModule],
  controllers: [AppController],
  providers: [AppService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule {}
</code></pre>
<p>Then save and confirm from your console if the database has been connected successfully.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Screenshot_2024_04_19-1.png" alt="db_conn_success" width="600" height="400" loading="lazy">
_show_db_success<em>conn</em></p>
<p>If you see the database connected successfully, good job! Otherwise, go back to the previous steps to see if you followed the configurations correctly.</p>
<p>Now, we can continue to consume our <code>datasource</code> service leveraging the TypeORM.</p>
<p>Let's create <code>users</code> module, controller, provider and entity to interact with our newly connected database.</p>
<pre><code class="lang-bash">nest g module users &amp;&amp; nest g service users &amp;&amp; nest g controller users
</code></pre>
<p>The above command will generate the <code>users</code> module, service and controller and update the <strong>app.module.ts</strong> with the <code>users</code> module.</p>
<p>Add the following code inside the <strong>users.entity.ts</strong> file and restart your development server to create the <code>user</code> table in the database.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Column, Entity, PrimaryGeneratedColumn } <span class="hljs-keyword">from</span> <span class="hljs-string">'typeorm'</span>;

<span class="hljs-meta">@Entity</span>(<span class="hljs-string">'user'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UserEntity {
  <span class="hljs-meta">@PrimaryGeneratedColumn</span>()
  id: <span class="hljs-built_in">number</span>;

  <span class="hljs-meta">@Column</span>({ unique: <span class="hljs-literal">true</span> })
  username: <span class="hljs-built_in">string</span>;

  <span class="hljs-meta">@Column</span>()
  password: <span class="hljs-built_in">string</span>;
}
</code></pre>
<p>Check your Pgadmin 4 interface and confirm that TypeORM has automatically loaded the <code>UserEntity</code> and created the <code>user</code> table in your database, like so 👇.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Screenshot_2024_04_19-2.png" alt="confirm_user_table" width="600" height="400" loading="lazy">
_confirm_user<em>table</em></p>
<p>You might want to refresh the database if you don't see it at first.</p>
<p>Now let's implement our first <code>users</code> service handler, add the following code to your <strong>users.service.ts</strong> file:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> {
  HttpException,
  HttpStatus,
  Injectable,
  InternalServerErrorException,
  Logger,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { DataSource } <span class="hljs-keyword">from</span> <span class="hljs-string">'typeorm'</span>;
<span class="hljs-keyword">import</span> { UserEntity } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.entity'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> CreateUser {
  username: <span class="hljs-built_in">string</span>;
  password: <span class="hljs-built_in">string</span>;
}

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersService {
  <span class="hljs-keyword">private</span> userRepository;
  <span class="hljs-keyword">private</span> logger = <span class="hljs-keyword">new</span> Logger();
  <span class="hljs-comment">//   inject the Datasource provider</span>
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> dataSource: DataSource</span>) {
    <span class="hljs-comment">// get users table repository to interact with the database</span>
    <span class="hljs-built_in">this</span>.userRepository = <span class="hljs-built_in">this</span>.dataSource.getRepository(UserEntity);
  }
  <span class="hljs-comment">//  create handler to create new user and save to the database</span>
  <span class="hljs-keyword">async</span> createUser(createUser: CreateUser): <span class="hljs-built_in">Promise</span>&lt;UserEntity&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userRepository.create(createUser);
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userRepository.save(user);
    } <span class="hljs-keyword">catch</span> (err) {
      <span class="hljs-keyword">if</span> (err.code == <span class="hljs-number">23505</span>) {
        <span class="hljs-built_in">this</span>.logger.error(err.message, err.stack);
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> HttpException(<span class="hljs-string">'Username already exists'</span>, HttpStatus.CONFLICT);
      }
      <span class="hljs-built_in">this</span>.logger.error(err.message, err.stack);
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> InternalServerErrorException(
        <span class="hljs-string">'Something went wrong, Try again!'</span>,
      );
    }
  }
}
</code></pre>
<p>We've added the <code>createUser</code> method to handle creating a user when a POST request is sent with the required request body to the endpoint controller that utilizes the <code>createUser</code> service method. </p>
<p>The function takes an object <code>createUser</code> as an argument of type <code>CreateUser</code> interface. Usually, this should be a DTO (Data Transfer Object) for the data type structure and validation, but since it is out of the scope of this tutorial, we're using the interface just for the data shape. </p>
<p>We called the <code>create</code> method of the <code>userRepository</code> then assigned it's return to the <code>user</code> variable to hold the newly created user object. We then called the <code>save</code> method to save the object to the database.</p>
<p>Now, let's utilize the <code>createUser</code> service handler in our <code>users</code> controller that handles the POST request to create new user.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Body, Controller, Post } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { CreateUser, UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.service'</span>;

<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'users'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersController {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> userService: UsersService</span>) {}

  <span class="hljs-meta">@Post</span>(<span class="hljs-string">'/create'</span>)
  <span class="hljs-comment">//   handles the post request to /users/create endpoint to create new user</span>
  <span class="hljs-keyword">async</span> signUp(<span class="hljs-meta">@Body</span>() user: CreateUser) {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userService.createUser(user);
  }
}
</code></pre>
<p>Test the newly created endpoint, by sending a POST request to <code>http://localhost:3000/users/create</code> with the username and password as the request body.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Screenshot_2024_04_19-3.png" alt="test_user_create" width="600" height="400" loading="lazy">
_test_user_create<em>endpoint</em></p>
<p>Alright, let's check the database just to be sure that's all, because we already got a 201 response status code which should be enough to know that our application is smoothly interacting with our database using the TypeORM Datasource.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Screenshot_2024_04_19-4.png" alt="confirm_user_db" width="600" height="400" loading="lazy">
_confirm_user<em>db</em></p>
<h3 id="heading-extending-the-datasource-repository-for-custom-methods">Extending The DataSource Repository For Custom Methods</h3>
<p>Whether you're looking to optimize database queries, introduce new data manipulation operations, or integrate with third-party services, extending the DataSource repository with custom methods can be a game-changer interacting with the database seamlessly. </p>
<p>Here, we'll explore the benefits of custom methods, and provide a step-by-step guide to implementing them in your NestJS applications. So, let's dive in and unlock the full potential of the DataSource repository!</p>
<p>Some of the basic benefits of repository custom methods are:</p>
<p><strong>Tailored Functionality:</strong> Custom methods allow developers to introduce specific functionalities that are not available in the standard DataSource repository. By tailoring the DataSource repository with custom methods, developers can address unique use cases, data manipulation operations and aggregations, or optimizations that are essential for their project requirements.</p>
<p><strong>Optimized Performance:</strong> Custom methods can be designed to optimize database queries, data retrieval, and data manipulation operations, leading to improved performance and efficiency. By leveraging custom methods, developers can implement optimized algorithms, caching mechanisms, or query optimizations tailored to the specific needs and characteristics of their applications.</p>
<p><strong>Improved Code Reusability and Maintainability:</strong> Custom methods promote code reusability by encapsulating specific logic, algorithms, or operations within reusable components. By modularizing the custom methods, developers can maintain cleaner, more organized, and maintainable codebases, making it easier to manage, debug, and enhance the DataSource repository in the long run.</p>
<p>Ok, That's that, let's move to the action. So, we have a simple CRM application that has to do with user management. Let's add a custom repository method that can help us filter users by username.</p>
<p>To implement this, let's create our <code>datasource</code> module and <code>datasource</code> service. We're going to create these files to to align with the modularity principles of the NestJS architectural pattern.</p>
<p>Create the files inside your previously created <strong>datasource</strong> folder and add the following code:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// datasource.module.ts</span>
<span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { TypeOrmModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./typeorm.module'</span>;
<span class="hljs-keyword">import</span> { DataSourceService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./datasource.service'</span>;

<span class="hljs-meta">@Module</span>({
  imports: [TypeOrmModule],
  providers: [DataSourceService],
  <span class="hljs-built_in">exports</span>: [DataSourceService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> DataSourceModule {}
</code></pre>
<pre><code class="lang-typescript"><span class="hljs-comment">// datasource.service.ts</span>
<span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { UserEntity } <span class="hljs-keyword">from</span> <span class="hljs-string">'src/users/users.entity'</span>;
<span class="hljs-keyword">import</span> { DataSource } <span class="hljs-keyword">from</span> <span class="hljs-string">'typeorm'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> UsernameQuery {
  username: <span class="hljs-built_in">string</span>;
}

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> DataSourceService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> dataSource: DataSource</span>) {}

  <span class="hljs-comment">//   extend userRepository to add custom methods</span>
  userCustomRepository = <span class="hljs-built_in">this</span>.dataSource.getRepository(UserEntity).extend({
    <span class="hljs-keyword">async</span> filterUser(usernameQuery: UsernameQuery): <span class="hljs-built_in">Promise</span>&lt;UserEntity[]&gt; {
      <span class="hljs-keyword">const</span> { username } = usernameQuery;
      <span class="hljs-built_in">console</span>.log(username);
      <span class="hljs-comment">// initialize a query builder for the userrepository</span>
      <span class="hljs-keyword">const</span> query = <span class="hljs-built_in">this</span>.createQueryBuilder(<span class="hljs-string">'user'</span>);
      <span class="hljs-comment">//   filter user where username is like the passed username</span>
      query.where(<span class="hljs-string">'(LOWER(user.username) LIKE LOWER(:username))'</span>, {
        username: <span class="hljs-string">`%<span class="hljs-subst">${username}</span>%`</span>,
      });
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> query.getMany();
    },
  });
}
</code></pre>
<p>From the above <strong>datasource.service.ts</strong> code, we've extended the <code>UserRepository</code>, by calling the <code>getRepository</code> method on the <code>dataSource</code> service and passing <code>UserEntity</code> as an argument to get the repository for the particular table.</p>
<p>Then we called the <code>extend</code> method on the <code>userRepository</code> we got back from our <code>getRepository</code> to add our custom method. In our <code>extend</code> method, we passed an object that will contain all our custom methods for the custom repository we've assigned to the <code>userCustomRepository</code>.  Here, we've simply added just one custom method to our custom user repository which is <code>filterUser</code>. It runs a filter query on the user table by the username provided.</p>
<p>Since our <code>DataSourseService</code> is an injectable, we can inject it in our <code>UserService</code> and consume the newly created <code>filterUser</code> method after adding the <code>DataSourceModule</code> to the imports array of the user module like so 👇</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// users.module.ts</span>
<span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { UsersController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.controller'</span>;
<span class="hljs-keyword">import</span> { UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.service'</span>;
<span class="hljs-keyword">import</span> { DataSourceModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'src/datasource/datasource.module'</span>;

<span class="hljs-meta">@Module</span>({
  imports: [DataSourceModule], <span class="hljs-comment">// add the DataSourceModule to the import array </span>
  providers: [UsersService],
  controllers: [UsersController],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersModule {}
</code></pre>
<p>Let's consume the filter method from <code>CustomUserRepository</code> in our <code>UserService</code> to filter users by any username passed as our query argument when sending the request.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// users.service.ts</span>
<span class="hljs-keyword">import</span> {
  HttpException,
  HttpStatus,
  Injectable,
  InternalServerErrorException,
  Logger,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { DataSource } <span class="hljs-keyword">from</span> <span class="hljs-string">'typeorm'</span>;
<span class="hljs-keyword">import</span> { UserEntity } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.entity'</span>;
<span class="hljs-keyword">import</span> {
  DataSourceService,
  UsernameQuery,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'src/datasource/datasource.service'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> CreateUser {
  username: <span class="hljs-built_in">string</span>;
  password: <span class="hljs-built_in">string</span>;
}

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersService {
  <span class="hljs-keyword">private</span> userRepository;
  <span class="hljs-keyword">private</span> customUserRepository;
  <span class="hljs-keyword">private</span> logger = <span class="hljs-keyword">new</span> Logger();
  <span class="hljs-comment">//   inject the Datasource provider</span>
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
    <span class="hljs-keyword">private</span> dataSource: DataSource,
    <span class="hljs-keyword">private</span> dataSourceService: DataSourceService, <span class="hljs-comment">// inject our datasource service</span>
  </span>) {
    <span class="hljs-comment">// get users table repository to interact with the database</span>
    <span class="hljs-built_in">this</span>.userRepository = <span class="hljs-built_in">this</span>.dataSource.getRepository(UserEntity);
    <span class="hljs-comment">// assigning the dataSourceService userCustomRepository to the class customUserRepository</span>
    <span class="hljs-built_in">this</span>.customUserRepository = <span class="hljs-built_in">this</span>.dataSourceService.userCustomRepository;
  }
  <span class="hljs-comment">//  create handler to create new user and save to the database</span>
  <span class="hljs-keyword">async</span> createUser(createUser: CreateUser): <span class="hljs-built_in">Promise</span>&lt;UserEntity&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userRepository.create(createUser);
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userRepository.save(user);
    } <span class="hljs-keyword">catch</span> (err) {
      <span class="hljs-keyword">if</span> (err.code == <span class="hljs-number">23505</span>) {
        <span class="hljs-built_in">this</span>.logger.error(err.message, err.stack);
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> HttpException(<span class="hljs-string">'Username already exists'</span>, HttpStatus.CONFLICT);
      }
      <span class="hljs-built_in">this</span>.logger.error(err.message, err.stack);
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> InternalServerErrorException(
        <span class="hljs-string">'Something went wrong, Try again!'</span>,
      );
    }
  }
  <span class="hljs-comment">// the userService filterByUsername handler</span>
  <span class="hljs-keyword">async</span> filterByUsername(usernameQuery: UsernameQuery): <span class="hljs-built_in">Promise</span>&lt;UserEntity[]&gt; {
    <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// calling the customUserRepository filterUser custom method</span>
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.customUserRepository.filterUser(usernameQuery);
    } <span class="hljs-keyword">catch</span> (err) {
      <span class="hljs-built_in">this</span>.logger.error(err.message, err.stack);
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> InternalServerErrorException(
        <span class="hljs-string">'Something went wrong, Try again!'</span>,
      );
    }
  }
}
</code></pre>
<p>From the above, code we've injected our custom <code>DataSourceService</code> by adding the following to the class constructor <code>private dataSourceService: DataSourceService,</code>.</p>
<p>The <code>filterByUsername</code> service handles the request we consume in our custom <code>filterUser</code> method <code>await _this_.customUserRepository.filterUser(usernameQuery);</code>, which will return a promise.</p>
<p>Now, let's utilize this service handler in our user controller to filter users by their username.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// users.controller.ts</span>
<span class="hljs-keyword">import</span> { Body, Controller, Get, Post, Query } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { CreateUser, UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.service'</span>;
<span class="hljs-keyword">import</span> { UserEntity } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.entity'</span>;
<span class="hljs-keyword">import</span> { UsernameQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">'src/datasource/datasource.service'</span>;

<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'users'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersController {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> userService: UsersService</span>) {}

  <span class="hljs-meta">@Post</span>(<span class="hljs-string">'/create'</span>)
  <span class="hljs-comment">//   handles the post request to /users/create endpoint to create new user</span>
  <span class="hljs-keyword">async</span> signUp(<span class="hljs-meta">@Body</span>() user: CreateUser): <span class="hljs-built_in">Promise</span>&lt;UserEntity&gt; {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userService.createUser(user);
  }

  <span class="hljs-meta">@Get</span>(<span class="hljs-string">''</span>) <span class="hljs-comment">// get request handler that returns the filtered results of the users table</span>
  <span class="hljs-keyword">async</span> filterUser(
    <span class="hljs-meta">@Query</span>() usernameQuery: UsernameQuery <span class="hljs-comment">// extracts the username query param for the endpoint url,</span>
  ): <span class="hljs-built_in">Promise</span>&lt;UserEntity[]&gt; {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userService.filterByUsername(usernameQuery);
  }
}
</code></pre>
<p>Test our filter endpoint,</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Screenshot_2024_04_19-5.png" alt="test-filter" width="600" height="400" loading="lazy">
_test_filter<em>endpoint</em></p>
<p>Here, we got back a list with one user object with username like the username we passed as a query.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Voila! That's it, now you ready to start working with NestJS, TypeORM, and DataSource.</p>
<p>Thanks for reading!</p>
<p>If you've found it helpful, please share it with your friends and colleagues! Stay tuned for more insightful content, and let's continue learning and growing together. Cheers to building smarter, more efficient solutions with NestJS!</p>
<h3 id="heading-resources">Resources</h3>
<ul>
<li><a target="_blank" href="https://docs.nestjs.com/">NestJS Docs Page</a> </li>
<li><a target="_blank" href="https://typeorm.io/">TypeORM Docs Page</a></li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=sFnAHC9lLaw&amp;t=935s">Learn NestJS Complete Course</a></li>
</ul>
<h3 id="heading-contact-links">Contact Links</h3>
<ul>
<li><a target="_blank" href="https://twitter.com/ayobamialaran">Twitter</a></li>
<li><a target="_blank" href="https://www.linkedin.com/in/ayobami-alaran/">LinkedIn</a></li>
<li><a target="_blank" href="https://github.com/Ayobami6">GitHub</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Send Emails With Nodemailer in NestJS ]]>
                </title>
                <description>
                    <![CDATA[ By Okure U. Edet While learning Nestjs, I wanted to be able to send test emails with Nodemailer but I had difficulty doing this in the context of a NestJS application. I searched the internet for a solution and after much research, I found one. It tu... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-nodemailer-in-nestjs/</link>
                <guid isPermaLink="false">66d4608df855545810e934b3</guid>
                
                    <category>
                        <![CDATA[ email ]]>
                    </category>
                
                    <category>
                        <![CDATA[ nestjs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ projects ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 10 Apr 2024 11:52:29 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/joanna-kosinska-uGcDWKN91Fs-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Okure U. Edet</p>
<p>While learning Nestjs, I wanted to be able to send test emails with Nodemailer but I had difficulty doing this in the context of a NestJS application. I searched the internet for a solution and after much research, I found one. It turned out to be really simple.</p>
<p>In this article, I will share my solution so you can use it in your NestJS projects.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-how-to-set-up-a-nestjs-project">How to Set Up a NestJS Project</a></li>
<li><a class="post-section-overview" href="#heading-how-to-configure-nodemailer-in-your-app">How to Configure Nodemailer in Your App</a></li>
<li><a class="post-section-overview" href="#heading-how-to-send-emails-with-nodemailer">How to Send emails with Nodemailer</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h3 id="heading-how-to-set-up-a-nestjs-project">How to Set Up a NestJS Project</h3>
<p>Ideally, when a user clicks on a forget password route, a link should be sent to the user's email, and through that link, the user should be able to reset their password. This article will demonstrate a test case scenario of how this works using Nodemailer.</p>
<p>Open your favorite IDE or navigate to the terminal and paste the following command:</p>
<pre><code>$ npm i -g @nestjs/cli
$ nest <span class="hljs-keyword">new</span> nodemailer-app
</code></pre><p>The above commands generates a new project called  <code>nodemailer-app</code>. </p>
<p>After doing this, navigate to your project folder and install the Nodemailer packages, <code>npm i --save @nestjs-modules/mailer nodemailer</code> and types, <code>npm i --save-dev @types/nodemailer</code>.</p>
<h3 id="heading-how-to-configure-nodemailer-in-your-app">How to Configure Nodemailer in Your App</h3>
<p>Before moving on, make sure you have an account on <a target="_blank" href="https://mailtrap.io/">mailtrap.io</a>. If you do, just login and navigate to <strong>Email Testing</strong>. Create your own inbox if you don't have one. Navigate to the inbox and you should see your credentials which will be used to configure Nodemailer in your application.</p>
<p>In your project directory, go to the app module file and configure the package:</p>
<pre><code><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { AppController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.controller'</span>;
<span class="hljs-keyword">import</span> { AppService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.service'</span>;
<span class="hljs-keyword">import</span> { AuthModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./auth/auth.module'</span>;
<span class="hljs-keyword">import</span> { MailerModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs-modules/mailer'</span>;

@Module({
  <span class="hljs-attr">imports</span>: [
    AuthModule,
    MailerModule.forRoot({
      <span class="hljs-attr">transport</span>: {
        <span class="hljs-attr">host</span>: process.env.EMAIL_HOST,
        <span class="hljs-attr">auth</span>: {
          <span class="hljs-attr">user</span>: process.env.EMAIL_USERNAME,
          <span class="hljs-attr">pass</span>: process.env.EMAIL_PASSWORD,
        },
      },
    }),
  ],
  <span class="hljs-attr">controllers</span>: [AppController],
  <span class="hljs-attr">providers</span>: [AppService],
})
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppModule</span> </span>{}
</code></pre><p>In the above code, you imported the <code>MailerModule</code> from <code>@nestjs-modules/mailer</code>. Then you called a <code>forRoot()</code> method on it. Inside the <code>forRoot()</code> method, you specified a transport property which contains the host and auth properties.</p>
<p>Do not forget to get the host, port, username and password from your credentials in your inbox on <a target="_blank" href="https://mailtrap.io/">mailtrap.io</a>.</p>
<p>You can create a <code>.env</code> file which would house all your credential details. It is advisable to do so. To be able to load the appropriate <code>.env</code> file in NestJS, install this:</p>
<pre><code>$ npm i --save @nestjs/config
</code></pre><p>Then in your <code>app.module.ts</code> file, import a <code>ConfigModule</code>:</p>
<pre><code><span class="hljs-keyword">import</span> { ConfigModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/config'</span>;
</code></pre><p>Still in your <code>app.module.ts</code></p>
<pre><code><span class="hljs-comment">// include the config module in your imports array</span>

@Module({
  <span class="hljs-attr">imports</span>: [
    ConfigModule.forRoot({ <span class="hljs-attr">envFilePath</span>: <span class="hljs-string">'.env'</span>, <span class="hljs-attr">isGlobal</span>: <span class="hljs-literal">true</span> }),
  ],
  <span class="hljs-attr">controllers</span>: [AppController],
  <span class="hljs-attr">providers</span>: [AppService],
})
</code></pre><h3 id="heading-how-to-send-emails-with-nodemailer">How to Send Emails with NodeMailer</h3>
<p>After configuring Nodemailer, it is time to send emails with it.</p>
<p>In your <code>app.service.ts</code> file, paste the following code:</p>
<pre><code><span class="hljs-keyword">import</span> { MailerService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs-modules/mailer'</span>;
<span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

@Injectable()
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppService</span> </span>{
  <span class="hljs-keyword">constructor</span>(private readonly mailService: MailerService) {}

  sendMail() {
    <span class="hljs-keyword">const</span> message = <span class="hljs-string">`Forgot your password? If you didn't forget your password, please ignore this email!`</span>;

    <span class="hljs-built_in">this</span>.mailService.sendMail({
      <span class="hljs-attr">from</span>: <span class="hljs-string">'Kingsley Okure &lt;kingsleyokgeorge@gmail.com&gt;'</span>,
      <span class="hljs-attr">to</span>: <span class="hljs-string">'joanna@gmail.com'</span>,
      <span class="hljs-attr">subject</span>: <span class="hljs-string">`How to Send Emails with Nodemailer`</span>,
      <span class="hljs-attr">text</span>: message,
    });
  }
}
</code></pre><p>In the <code>app.service.ts</code> file, the <code>MailerService</code> is injected and then used in the class to send the email. Inside the class, the <code>MailerService</code> has a <code>sendMail</code> function which takes in an object as a parameter. The object contains a <code>from</code>, <code>to</code>, <code>subject</code> and <code>text</code> property.</p>
<p>Once you have done this, in the <code>app.controller.ts</code> file, paste the following code:</p>
<pre><code><span class="hljs-keyword">import</span> { Controller, Get, Res } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { AppService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.service'</span>;

@Controller()
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppController</span> </span>{
  <span class="hljs-keyword">constructor</span>(private readonly appService: AppService) {}

  @Get()
  sendMailer(@Res() response: any) {
    <span class="hljs-keyword">const</span> mail = <span class="hljs-built_in">this</span>.appService.sendMail();

    <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">200</span>).json({
      <span class="hljs-attr">message</span>: <span class="hljs-string">'success'</span>,
      mail,
    });
  }
}
</code></pre><p>All that is done in the controller is to create a <code>Get</code> request which will call the <code>sendMail</code> function you have created in the service.</p>
<p>Ideally, in a real world application, all this will be done in a forgot password function. And an email will be sent to the user once they click on a forgot password route.</p>
<p>To test this little setup, open your Postman and go to localhost:3000 and hit send.</p>
<p>Then go to your <a target="_blank" href="https://mailtrap.io/inboxes/2445842/messages">mailtrap.io</a> inbox and see your message.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>In this article, you have learned how to send emails with Nodemailer, a software designed to help developers send emails to multiple people at once. </p>
<p>You have also learned how to configure and set it up in the context of a NestJs application.</p>
<p>If you want to connect with me, you can follow me on <a target="_blank" href="https://twitter.com/itzz_okure">Twitter</a> or on <a target="_blank" href="https://www.linkedin.com/in/okure/">Linkedin</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Comprehensive NestJS Course ]]>
                </title>
                <description>
                    <![CDATA[ NestJS is a progressive Node.js framework for building efficient, reliable, and scalable server-side applications using TypeScript and JavaScript.  Learning NestJS can significantly enhance your ability to create structured, maintainable, and testabl... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/comprehensive-nestjs-course/</link>
                <guid isPermaLink="false">66b2015b08bc664c3c097e5d</guid>
                
                    <category>
                        <![CDATA[ nestjs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Tue, 26 Mar 2024 20:27:32 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/03/nextjsfull.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>NestJS is a progressive Node.js framework for building efficient, reliable, and scalable server-side applications using TypeScript and JavaScript. </p>
<p>Learning NestJS can significantly enhance your ability to create structured, maintainable, and testable backend applications, offering a robust toolkit that integrates seamlessly with other modern technologies and methodologies.</p>
<p>We just posted a comprehensive NestJS course on the freeCodeCamp.org YouTube channel. This course, crated by the experienced Haider Malik, will help you master the creation of robust backend APIs for real-world applications.</p>
<p>In this course, Haider Malik, a seasoned web developer and open-source advocate, will guide you through the process of developing Spotify clone backend. Starting from database design to REST API development and deployment, this course is structured to provide a deep understanding of backend architecture using a blend of NestJS, Node.js, PostgreSQL, and MongoDB.</p>
<p>The course contains multiple modules, each designed to tackle different aspects of backend development with NestJS. From understanding the basics of NestJS, creating REST APIs, handling middlewares and exception filters, to implementing authentication and authorization, the course is a deep dive into backend development.</p>
<p>Further modules cover advanced topics like connecting with databases using TypeORM, implementing relationships in databases, and securing APIs with JWT authentication. Learners will also get hands-on experience with migrations, seeding, debugging, and even deploying NestJS applications to cloud services.</p>
<p>The course does not stop at REST APIs; it also introduces GraphQL, showcasing how to build and authenticate GraphQL APIs. Advanced concepts like WebSocket integration, file handling, custom decorators, and even real-time subscriptions with GraphQL are covered, ensuring learners are well-versed in the latest backend development practices.</p>
<p>Here is the full course outline.</p>
<h3 id="heading-module-0">Module 0</h3>
<ul>
<li>What is Nestjs</li>
<li>Create NestJs Project</li>
<li>Nestjs Directory Structure</li>
</ul>
<h3 id="heading-module-1">Module 1</h3>
<ul>
<li>Creating Controller</li>
<li>Creating a Service</li>
<li>Creating Module</li>
</ul>
<h3 id="heading-module-2">Module 2</h3>
<ul>
<li>Middleware</li>
<li>Exception Filter</li>
<li>Transform param using ParseIntPipe</li>
<li>Validate Request Body using class validator</li>
</ul>
<h3 id="heading-module-3">Module 3</h3>
<ul>
<li>Custom Providers</li>
<li>Injection Scopes</li>
<li>One To Many Relation</li>
</ul>
<h3 id="heading-module-4">Module 4</h3>
<ul>
<li>Establish Database Connection</li>
<li>Create an Entity</li>
<li>Create and Fetch records from Database</li>
<li>Pagination</li>
</ul>
<h3 id="heading-module-5">Module 5</h3>
<ul>
<li>One to One</li>
<li>Many to Many relation</li>
</ul>
<h3 id="heading-module-6">Module 6</h3>
<ul>
<li>User Signup</li>
<li>User Login</li>
<li>Authenticate User with Passport JWT</li>
<li>Role Based Authentication</li>
<li>Two Factor Authentication</li>
<li>API Key Authentication</li>
</ul>
<h3 id="heading-module-7">Module 7</h3>
<ul>
<li>Debug Nestjs Application</li>
<li>Migrations</li>
<li>Seeding</li>
</ul>
<h3 id="heading-module-8">Module 8</h3>
<ul>
<li>Custom Configuration</li>
<li>Validate Env Variables</li>
<li>Hot Module Reloading</li>
</ul>
<h3 id="heading-module-9">Module 9</h3>
<ul>
<li>Swagger Setup</li>
<li>Document Signup Route</li>
<li>Create Schema using ApiProperty</li>
<li>Test JWT Authentication</li>
</ul>
<h3 id="heading-module-10">Module 10</h3>
<ul>
<li>Install MongoDB using Docker Compose</li>
<li>Connect with MongoDB</li>
<li>Create Schema</li>
<li>Save Record in Mongo Collection</li>
<li>Find and Delete</li>
<li>Populate</li>
</ul>
<h3 id="heading-module-11">Module 11</h3>
<ul>
<li>Configure Dev and Production Env</li>
<li>Push Source Code to Github Repo</li>
<li>Deploy Nestjs Project to Railway</li>
<li>Install Dotenv to work with TypeORM migrations</li>
<li>Fixing Env Bugs</li>
</ul>
<h3 id="heading-module-12">Module 12</h3>
<ul>
<li>Getting started with Jest</li>
<li>Auto Mocking</li>
<li>SpyOn Function</li>
<li>Unit Test Controller</li>
<li>Unit Test Service</li>
<li>E2E Testing</li>
</ul>
<h3 id="heading-module-13">Module 13</h3>
<ul>
<li>Speedy Web Compiler with Nestjs v10</li>
<li>Creating Websocket Server</li>
<li>Send Message from Frontend app</li>
</ul>
<h3 id="heading-module-14">Module 14</h3>
<ul>
<li>GraphQL Server Setup</li>
<li>Define Queries and Mutations</li>
<li>Resolve Queries</li>
<li>Resolve Mutations</li>
<li>Error Handling</li>
</ul>
<h3 id="heading-module-15">Module 15</h3>
<ul>
<li>Define Schema for Authentication</li>
<li>Resolve Auth Queries and Mutations</li>
<li>Apply Authentication using Auth Guard</li>
</ul>
<h3 id="heading-module-16">Module 16</h3>
<ul>
<li>Implement Real time Subscription</li>
</ul>
<h3 id="heading-module-17">Module 17</h3>
<ul>
<li>Unit Test Resolver</li>
<li>End to End Testing GraphQL APIs</li>
</ul>
<h3 id="heading-module-18">Module 18</h3>
<ul>
<li>Server Side Caching using Apollo</li>
<li>Optimize Query Performance using Data Loader</li>
<li>Fetching Data from External REST API</li>
</ul>
<h3 id="heading-module-19">Module 19</h3>
<ul>
<li>Setup Prisma</li>
<li>Models and Migrations</li>
<li>Generate Prisma Client</li>
<li>Create, Find and FindOne</li>
<li>Update and Delete Operation.mov</li>
<li>One to Many Relation</li>
<li>One to One Relation</li>
<li>Many to Many Relation</li>
<li>Bulk or Batch Operations</li>
<li>Implement Transaction using Nested Queries</li>
<li>Interactive Transactions</li>
</ul>
<h3 id="heading-module-20">Module 20</h3>
<ul>
<li>File Upload</li>
<li>Custom Decorator</li>
<li>Scheduling CRON Task with Nest.js</li>
<li>Cookies</li>
<li>Queues</li>
<li>Event Emitter</li>
<li>Streaming</li>
<li>Session</li>
</ul>
<p>Each lesson is designed to be highly practical, ensuring that learners not only understand the theoretical aspects but also get to implement what they've learned in real-world scenarios. This hands-on approach, combined with Haider's expert guidance, ensures that by the end of the course, participants will be confident in building and deploying robust backend systems.</p>
<p>Watch the full course on <a target="_blank" href="https://www.youtube.com/watch?v=sFnAHC9lLaw">the freeCodeCamp.org YouTube channel</a> (14-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/sFnAHC9lLaw" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Add Filtering, Sorting, Limiting, and Pagination to Your Nest.js App ]]>
                </title>
                <description>
                    <![CDATA[ By Okure U. Edet If you are reading this article, you are probably a developer who has used an API to call data for your application. You may have also used features such as filtering and pagination to limit the amount of data you want to receive.  T... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-add-filtering-sorting-limiting-pagination-to-nestjs-app/</link>
                <guid isPermaLink="false">66d46089ffe6b1f641b5fa4b</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ nestjs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 05 Feb 2024 19:01:33 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/nestjs-app-image.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Okure U. Edet</p>
<p>If you are reading this article, you are probably a developer who has used an API to call data for your application. You may have also used features such as filtering and pagination to limit the amount of data you want to receive. </p>
<p>These API features are important when building your own API. They help ensure that your API is fast, secure, and easily understandable by the people using it.</p>
<p>In this article, you will build a simple expense API with Nest.js and MongoDB for a database. You will then implement filtering, sorting, limiting, and pagination to make your API faster and easy to use. Let's begin!</p>
<h3 id="heading-heres-what-well-cover">Here's what we'll cover:</h3>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-an-api">What is an API?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-a-nestjs-app">How to set up a Nest.js app</a></li>
<li><a class="post-section-overview" href="#heading-how-to-configure-mongodb">How to configure MongoDB</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-expense-endpoints">How to set up the expense endpoints</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-filtering-and-sorting">How to implement filtering and sorting</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-limiting-and-pagination">How to implement limiting and pagination</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h2 id="heading-what-is-an-api">What is an API?</h2>
<p>APIs are the backbone of modern software development. API stands for Application Programming Interface, and it allows one piece of software to communicate with another piece of software. </p>
<p>Web APIs use the HTTP communication protocols to communicate with computers. There are different types of APIs, but we won't get into them here.</p>
<p>These days, it's common for web APIs to have design features such as filtering, sorting, limiting, and pagination to make the API faster, easier to use, and more secure. You will learn how to implement these features to make a better API in this article.</p>
<h2 id="heading-how-to-set-up-a-nestjs-app">How to Set Up a Nest.js App</h2>
<p>First of all, you will be building a simple expense CRUD API in Nestjs. Nestjs is a progressive Node.js framework for building modern APIs that's pretty easy to use.</p>
<p>To get started, open your command line and type out the following commands:</p>
<pre><code>$ npm i -g @nestjs/cli
$ nest <span class="hljs-keyword">new</span> expense-app
</code></pre><p>Follow the installation guide. This will generate a few boilerplate files for you. Then you can open your Nest.js app in an IDE of your choice.</p>
<h2 id="heading-how-to-configure-mongodb">How to Configure MongoDB</h2>
<p>Since MongoDB is our preferred database, it's important to configure it so you can use it in your app. First install the <code>@nestjs/mongoose</code> package:</p>
<pre><code>$ npm i @nestjs/mongoose mongoose
</code></pre><p>Once the installation is complete, go into your app module file and import the <code>MongooseModule</code>:</p>
<pre><code><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { AppController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.controller'</span>;
<span class="hljs-keyword">import</span> { AppService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.service'</span>;
<span class="hljs-keyword">import</span> { MongooseModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;

@Module({
  <span class="hljs-attr">imports</span>: [MongooseModule.forRoot(<span class="hljs-string">`mongodb+srv://*******:*******@cluster0.30vt0jd.mongodb.net/expense-test-app`</span>)],
  <span class="hljs-attr">controllers</span>: [AppController],
  <span class="hljs-attr">providers</span>: [AppService],
})
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppModule</span> </span>{}
</code></pre><p>If you don't want to expose your string that way, you can create a <code>.env</code> file and store your database connection string in it. You will then need to install the <code>@nestjs/config</code> package which uses dotenv internally. </p>
<p>Inside your app module file, import the <code>ConfigModule</code>:</p>
<pre><code>@Module({
  <span class="hljs-attr">imports</span>: [
    ConfigModule.forRoot({ <span class="hljs-attr">envFilePath</span>: <span class="hljs-string">'.env'</span>, <span class="hljs-attr">isGlobal</span>: <span class="hljs-literal">true</span> }),
    MongooseModule.forRoot(process.env.DATABASE),
  ],
  <span class="hljs-attr">controllers</span>: [AppController],
  <span class="hljs-attr">providers</span>: [AppService],
})
</code></pre><p><code>isGlobal: true</code> is to make the module available everywhere in your application. <code>envFilePath</code> specifies the path to your <code>.env</code> file.</p>
<h2 id="heading-how-to-set-up-the-expense-endpoints">How to Set Up the Expense Endpoints</h2>
<p>You have configured MongoDB. Now it's time to set up the expense endpoints. </p>
<p>You can create a module in Nest.js by typing the following into the terminal: <code>nest generate module expenses</code>. You can also generate the controller like this: <code>nest generate controller expenses</code> and the service like this: <code>nest generate service expenses</code>. You should do all this in the src folder. </p>
<p>Go ahead and generate an expenses.schema.ts file. Inside the expenses.schema.ts file, create an expense schema with some validation.</p>
<pre><code><span class="hljs-keyword">import</span> { Prop, Schema, SchemaFactory } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;
<span class="hljs-keyword">import</span> mongoose, { HydratedDocument } <span class="hljs-keyword">from</span> <span class="hljs-string">'mongoose'</span>;

<span class="hljs-keyword">export</span> type ExpenseDocument = HydratedDocument&lt;Expense&gt;;

@Schema()
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Expense</span> </span>{
  @Prop({
    <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">required</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">'Title is required'</span>],
  })
  <span class="hljs-attr">title</span>: string;

  @Prop({
    <span class="hljs-attr">min</span>: <span class="hljs-number">0</span>,
    <span class="hljs-attr">required</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">'Amount is required'</span>],
  })
  <span class="hljs-attr">amount</span>: number;

  @Prop({
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">required</span>: [<span class="hljs-literal">true</span>, <span class="hljs-string">'Category is required'</span>],
  })
  <span class="hljs-attr">category</span>: string;

  @Prop({
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">Date</span>,
    <span class="hljs-attr">default</span>: <span class="hljs-built_in">Date</span>.now,
  })
  <span class="hljs-attr">incurred</span>: <span class="hljs-built_in">Date</span>;

  @Prop({ <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">trim</span>: <span class="hljs-literal">true</span> })
  <span class="hljs-attr">notes</span>: string;

  @Prop()
  <span class="hljs-attr">slug</span>: string;

  @Prop()
  <span class="hljs-attr">updated</span>: <span class="hljs-built_in">Date</span>;

  @Prop({
    <span class="hljs-attr">type</span>: <span class="hljs-built_in">Date</span>,
    <span class="hljs-attr">default</span>: <span class="hljs-built_in">Date</span>.now,
  })
  <span class="hljs-attr">created</span>: <span class="hljs-built_in">Date</span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ExpenseSchema = SchemaFactory.createForClass(Expense);
</code></pre><p>The properties in this schema include title, amount, category, notes, and slug.</p>
<p>After doing this, you want to register the expense model in the expenses.module.ts file:</p>
<pre><code><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { ExpensesController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./expenses.controller'</span>;
<span class="hljs-keyword">import</span> { ExpensesService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./expenses.service'</span>;
<span class="hljs-keyword">import</span> { MongooseModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;
<span class="hljs-keyword">import</span> { Expense, ExpenseSchema } <span class="hljs-keyword">from</span> <span class="hljs-string">'./expenses.schema'</span>;

@Module({
  <span class="hljs-attr">imports</span>: [
    MongooseModule.forFeature([{ <span class="hljs-attr">name</span>: Expense.name, <span class="hljs-attr">schema</span>: ExpenseSchema }]),
  ],
  <span class="hljs-attr">controllers</span>: [ExpensesController],
  <span class="hljs-attr">providers</span>: [ExpensesService],
})
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExpensesModule</span> </span>{}
</code></pre><p>Once you've registered the schema, you can then inject the <code>Expense</code> model into the <code>ExpensesService</code> by using an <code>@InjectModel()</code> decorator.</p>
<pre><code><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { InjectModel } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/mongoose'</span>;
<span class="hljs-keyword">import</span> { Expense } <span class="hljs-keyword">from</span> <span class="hljs-string">'./expenses.schema'</span>;
<span class="hljs-keyword">import</span> { Model } <span class="hljs-keyword">from</span> <span class="hljs-string">'mongoose'</span>;
<span class="hljs-keyword">import</span> { ExpenseDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/expense.dto'</span>;

@Injectable()
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExpensesService</span> </span>{
  <span class="hljs-keyword">constructor</span>(
    @InjectModel(Expense.name) private expenseModel: Model&lt;Expense&gt;,
  ) {}

  <span class="hljs-keyword">async</span> createExpense(data: ExpenseDto) {
    <span class="hljs-keyword">const</span> expense = <span class="hljs-built_in">this</span>.expenseModel.create(data);

    <span class="hljs-keyword">return</span> expense;
  }

  <span class="hljs-keyword">async</span> getExpenses() {
    <span class="hljs-keyword">const</span> expenses = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.expenseModel.find();

    <span class="hljs-keyword">return</span> expenses;
  }
}
</code></pre><p>In the <code>ExpensesService</code> file, we injected the <code>Expense</code> model as a dependency using the <code>@InjectModel()</code> decorator. Once you've done this, you then go ahead and define a function that creates an expense and a function that gets all expenses.</p>
<p>In your controller, add the following code:</p>
<pre><code><span class="hljs-keyword">import</span> { Body, Controller, Get, Post, Res } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { ExpensesService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./expenses.service'</span>;
<span class="hljs-keyword">import</span> { ExpenseDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/expense.dto'</span>;

@Controller(<span class="hljs-string">'expenses'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExpensesController</span> </span>{
  <span class="hljs-keyword">constructor</span>(private readonly expenseService: ExpensesService) {}

  @Post()
  <span class="hljs-keyword">async</span> createExpense(@Body() data: ExpenseDto, @Res() response: any) {
    <span class="hljs-keyword">const</span> expense = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.expenseService.createExpense(data);
    <span class="hljs-built_in">console</span>.log(expense);

    <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">201</span>).json({
      <span class="hljs-attr">message</span>: <span class="hljs-string">'success'</span>,
      <span class="hljs-attr">data</span>: expense,
    });
  }

  @Get()
  <span class="hljs-keyword">async</span> getExpenses(@Res() response: any) {
    <span class="hljs-keyword">const</span> expenses = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.expenseService.getExpenses();

    <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">200</span>).json({
      <span class="hljs-attr">message</span>: <span class="hljs-string">'success'</span>,
      <span class="hljs-attr">data</span>: expenses,
    });
  }
}
</code></pre><p>If you're getting a dependency error, navigate to your <code>app.module.ts</code> file and remove <code>ExpenseController</code> from the <code>controllers</code> array.</p>
<p>You can test the endpoint on Postman.</p>
<h2 id="heading-how-to-implement-filtering-and-sorting">How to Implement Filtering and Sorting</h2>
<p>Now that you have successfully set up the expense endpoints, it's time to implement filtering and sorting features in the API.</p>
<h3 id="heading-filtering">Filtering</h3>
<p>Filtering is essentially done in the same way we do it in Node.js.</p>
<p>Inside your src directory, create a new folder called <code>Utils</code> and inside that folder create a new file called <code>apiFeatures.ts</code>.</p>
<p>Inside this file, define a class called <code>APIFeatures</code>. This class will contain methods that will house the API features you'll implement.</p>
<pre><code><span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">APIFeatures</span> </span>{
  <span class="hljs-attr">mongooseQuery</span>: any;
  queryString: any;

  <span class="hljs-keyword">constructor</span>(mongooseQuery: any, queryString: any) {
    <span class="hljs-built_in">this</span>.mongooseQuery = mongooseQuery;
    <span class="hljs-built_in">this</span>.queryString = queryString;
  }

  filter() {
    <span class="hljs-comment">// 1) Filtering</span>
    <span class="hljs-keyword">const</span> queryObj = { ...this.queryString };
    <span class="hljs-keyword">const</span> excludedFields = [<span class="hljs-string">'page'</span>, <span class="hljs-string">'sort'</span>, <span class="hljs-string">'limit'</span>, <span class="hljs-string">'fields'</span>];
    excludedFields.forEach(<span class="hljs-function">(<span class="hljs-params">fields</span>) =&gt;</span> {
      <span class="hljs-keyword">delete</span> queryObj[fields];
    });
    <span class="hljs-comment">// console.log(queryObj);</span>

    <span class="hljs-comment">//2) Advanced filtering</span>
    <span class="hljs-keyword">let</span> queryStr = <span class="hljs-built_in">JSON</span>.stringify(queryObj);
    queryStr = queryStr.replace(<span class="hljs-regexp">/\b(gte|gt|lte|lt)\b/g</span>, <span class="hljs-function">(<span class="hljs-params">match</span>) =&gt;</span> <span class="hljs-string">`$<span class="hljs-subst">${match}</span>`</span>);
    <span class="hljs-comment">//console.log(JSON.parse(queryStr));</span>

    <span class="hljs-built_in">this</span>.mongooseQuery = <span class="hljs-built_in">this</span>.mongooseQuery.find(<span class="hljs-built_in">JSON</span>.parse(queryStr));

    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
  }
}
</code></pre><p>In the filter method, you created a hard copy of the <code>req.query</code>. It's passed as an argument in the form of <code>queryString</code>. </p>
<p>Before filtering, you want to exclude certain special fileds such as <code>page</code>, <code>sort</code>, <code>limits</code> and <code>fields</code>. These fields are deleted from the hard copy of the object which is stored in the variable <code>queryObj</code>. You also want to use MongoDB operators such as <code>gt</code> or <code>gte</code>.</p>
<p>For example, on Postman this is how you type in the query: <code>?amount[gt]=100</code>
In MongoDB, It'll look like this: <code>{ amount: { $gt: 100 } }</code>. In the filter method, we added a <code>$</code> sign to the operators using a regular expression.</p>
<p>After that, the object is parsed using <code>JSON.parse()</code> method and it is then passed into the Mongoose query function. Make sure you return the whole class itself by typing <code>return this</code>.</p>
<h3 id="heading-sorting">Sorting</h3>
<p>As you can see, implementing fitering is quite easy in Nest.js as it is in Node.js.</p>
<p>Now it's time to implement sorting. Inside the <code>APIFeatures</code> class, define another function called sorting.</p>
<pre><code>  sorting() {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.queryString.sort) {
      <span class="hljs-keyword">const</span> sortBy = <span class="hljs-built_in">this</span>.queryString.sort.split(<span class="hljs-string">','</span>).join(<span class="hljs-string">' '</span>);
      <span class="hljs-comment">// console.log(sortBy);</span>
      <span class="hljs-built_in">this</span>.mongooseQuery = <span class="hljs-built_in">this</span>.mongooseQuery.sort(sortBy);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">this</span>.mongooseQuery = <span class="hljs-built_in">this</span>.mongooseQuery.sort(<span class="hljs-string">'-created'</span>);
    }

    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
  }
</code></pre><p>The above method checks if a sort property exists on the query object. If it does, you split the string by a <code>,</code> in case there are multiple sort queries. Then you join it by a <code>' '</code>. </p>
<p>Once you've done this, you chain it to the Mongoose query with a sort method which exists on all documents. The else block sorts the document by the date it was created in case the user does not specify any sort query.</p>
<h2 id="heading-how-to-implement-limiting-and-pagination">How to Implement Limiting and Pagination</h2>
<p>Congrats! You have implemented filtering and sorting. Now it's time to implement limiting and pagination.</p>
<h3 id="heading-limiting">Limiting</h3>
<p>To limit fields, you can call the <code>select()</code> method on the Mongoose query.</p>
<p>Define another method in the class:</p>
<pre><code> limit() {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.queryString.fields) {
      <span class="hljs-keyword">const</span> fields = <span class="hljs-built_in">this</span>.queryString.fields.split(<span class="hljs-string">','</span>).join(<span class="hljs-string">' '</span>);

      <span class="hljs-built_in">this</span>.mongooseQuery = <span class="hljs-built_in">this</span>.mongooseQuery.select(fields);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">this</span>.mongooseQuery = <span class="hljs-built_in">this</span>.mongooseQuery.select(<span class="hljs-string">'-__v'</span>);
    }

    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
  }
</code></pre><p>And there you go.</p>
<h3 id="heading-pagination">Pagination</h3>
<p>To implement pagination, you want to get the <code>page</code> and <code>limit</code> from the query object. You then want to skip certain number of documents to get to the page you want. There is a <code>skip()</code> method and a <code>limit()</code> method on the Mongoose query.</p>
<pre><code>  pagination() {
    <span class="hljs-comment">// get the page and convert it to a number. If no page set default to 1</span>
    <span class="hljs-keyword">const</span> page = <span class="hljs-built_in">this</span>.queryString.page * <span class="hljs-number">1</span> || <span class="hljs-number">1</span>;

    <span class="hljs-comment">// get limit and if no limit, set limit to 100</span>
    <span class="hljs-keyword">const</span> limit = <span class="hljs-built_in">this</span>.queryString.limit * <span class="hljs-number">1</span> || <span class="hljs-number">100</span>;

    <span class="hljs-comment">// calculate skip value</span>
    <span class="hljs-keyword">const</span> skip = (page - <span class="hljs-number">1</span>) * limit;

    <span class="hljs-comment">// chain it to the mongoose query.</span>
    <span class="hljs-built_in">this</span>.mongooseQuery = <span class="hljs-built_in">this</span>.mongooseQuery.skip(skip).limit(limit);

    <span class="hljs-comment">// return the object</span>
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>;
  }
</code></pre><p>Once you've done this, you want to call the <code>APIfeatures</code> class in your <code>ExpensesService</code> class in your expenses.service.ts file.</p>
<p>Replace your <code>getExpenses</code> function with this code:</p>
<pre><code> <span class="hljs-keyword">async</span> getExpenses(query?: any) {
    <span class="hljs-keyword">const</span> features = <span class="hljs-keyword">new</span> APIFeatures(<span class="hljs-built_in">this</span>.expenseModel.find(), query)
      .filter()
      .sort()
      .limit()
      .pagination();
    <span class="hljs-comment">//Execute the query</span>
    <span class="hljs-keyword">const</span> expenses = <span class="hljs-keyword">await</span> features.mongooseQuery;

    <span class="hljs-keyword">return</span> expenses;
  }
</code></pre><p>In the function, it is possible to chain all these methods in the <code>APIFeatures</code> class because each method returns the object.</p>
<p>In your expenses.controller.ts file, your <code>getExpenses</code> function should look like this:</p>
<pre><code>  @Get()
  <span class="hljs-keyword">async</span> getExpenses(@Res() response: any, @Req() request: any) {
    <span class="hljs-keyword">const</span> expenses = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.expenseService.getExpenses(request.query);

    <span class="hljs-keyword">return</span> response.status(<span class="hljs-number">200</span>).json({
      <span class="hljs-attr">message</span>: <span class="hljs-string">'success'</span>,
      <span class="hljs-attr">data</span>: expenses,
    });
  }
</code></pre><p>Now run the application with <code>npm start:dev</code> and test your API features in Postman.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this guide, you have learned how to implement sorting, filtering, limiting, and pagination in your Nest.js applications. </p>
<p>With this knowledge, you can go ahead and implement these features in your personal projects built using Nest.js.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a CRUD REST API with NestJS, Docker, Swagger, and Prisma ]]>
                </title>
                <description>
                    <![CDATA[ Welcome to this in-depth guide on crafting a RESTful API with NestJS, Docker, Swagger, and Prisma. My goal here is to teach you how to build robust and efficient backends, regardless of whether you're a seasoned developer or a beginner just dipping y... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-crud-rest-api-with-nestjs-docker-swagger-prisma/</link>
                <guid isPermaLink="false">66bb56f70da5b03e481107bf</guid>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Docker ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                    <category>
                        <![CDATA[ nestjs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Isaiah Clifford Opoku ]]>
                </dc:creator>
                <pubDate>Tue, 23 Jan 2024 00:17:33 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/Nestjs_Free_code.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Welcome to this in-depth guide on crafting a RESTful API with NestJS, Docker, Swagger, and Prisma. My goal here is to teach you how to build robust and efficient backends, regardless of whether you're a seasoned developer or a beginner just dipping your toes into the world of coding.</p>
<p>In this journey, we'll be creating a delightful recipe management system. We'll explore the power of NestJS, Docker, Swagger, and Prisma, and harness these cutting-edge technologies to implement CRUD (Create, Read, Update, Delete) operations for managing recipes.</p>
<p>But this tutorial isn't just for the culinary enthusiasts or recipe collectors out there. It's for anyone who's passionate about learning and growing their development skills. </p>
<p>So, buckle up and get ready for an exciting coding adventure as we dive in and start building your very own recipe management system together.</p>
<p>This is what we'll build:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/all-for-swagger-end-product.png" alt="REST API ALL  " width="600" height="400" loading="lazy">
<em>A snapshot of the Swagger UI showcasing all the implemented endpoints.</em></p>
<p>And here's what we'll cover:</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-technologies">Technologies</a></li>
<li><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></li>
<li><a class="post-section-overview" href="#heading-development-environment">Development Environment</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-nestjs-project">How to Set Up the NestJS Project</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-postgresql-instance-with-docker">How to Create a PostgreSQL Instance with Docker</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-prisma">How to Set Up Prisma</a></li>
<li><a class="post-section-overview" href="#heading-how-to-initialize-prisma">How to Initialize Prisma</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-your-environment-variable">How to Set Your Environment Variable</a></li>
<li><a class="post-section-overview" href="#heading-understanding-the-prisma-schema">Understanding the Prisma Schema</a></li>
<li><a class="post-section-overview" href="#heading-how-to-model-the-data">How to Model the Data</a></li>
<li><a class="post-section-overview" href="#heading-how-to-migrate-the-database">How to Migrate the Database</a></li>
<li><a class="post-section-overview" href="#heading-how-to-seed-the-database">How to Seed the Database</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-a-prisma-service">How to Create a Prisma Service</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-swagger">How to Set Up Swagger</a></li>
<li><a class="post-section-overview" href="#heading-how-to-implement-crud-operations-for-the-recipe-model">How to Implement CRUD Operations for the Recipe Model</a></li>
<li><a class="post-section-overview" href="#heading-how-to-generate-rest-resources-with-nestjs-cli">How to Generate REST Resources with NestJS CLI</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-prismaclient-to-the-recipe-module">How to Add PrismaClient to the Recipe Module</a></li>
<li><a class="post-section-overview" href="#heading-how-to-define-the-get-recipes-endpoint">How to Define the GET /recipes Endpoint</a></li>
<li><a class="post-section-overview" href="#heading-how-to-define-the-get-recipesid-endpoint">How to Define the GET /recipes/:id Endpoint</a></li>
<li><a class="post-section-overview" href="#heading-how-to-define-the-post-recipes-endpoint">How to Define the POST /recipes Endpoint</a></li>
<li><a class="post-section-overview" href="#heading-how-to-define-the-patch-recipesid-endpoint">How to Define the PATCH /recipes/:id Endpoint</a></li>
<li><a class="post-section-overview" href="#heading-how-to-define-the-delete-recipesid-endpoint">How to Define the DELETE /recipes/:id Endpoint</a></li>
<li><a class="post-section-overview" href="#heading-summary-and-final-remarks">Summary and Final Remarks</a></li>
</ul>
<h2 id="heading-technologies">Technologies</h2>
<p>To build this application, we'll be leveraging the power of the following tools:</p>
<ul>
<li><strong><a target="_blank" href="https://nestjs.com/">NestJS</a></strong>: A progressive Node.js framework for building efficient, reliable, and scalable server-side applications.</li>
<li><strong><a target="_blank" href="https://www.prisma.io/">Prisma</a></strong>: An open-source database toolkit that makes it easy to reason about your data and how you interact with it.</li>
<li><strong><a target="_blank" href="https://www.postgresql.org/">PostgreSQL</a></strong>: A powerful, open source object-relational database system.</li>
<li><strong><a target="_blank" href="https://www.docker.com/">Docker</a></strong>: An open platform for developing, shipping, and running applications. Docker enables you to separate your applications from your infrastructure so you can deliver software quickly.</li>
<li><strong><a target="_blank" href="https://swagger.io/">Swagger</a></strong>: A tool for designing, building, and documenting RESTful APIs.</li>
<li><strong><a target="_blank" href="https://www.typescriptlang.org/">TypeScript</a></strong>: A statically typed superset of JavaScript that adds optional types, classes, and modules to the language.</li>
</ul>
<p>Each of these technologies plays a crucial role in creating a robust, scalable, and maintainable application. We'll dive deeper into each one as we proceed.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<h3 id="heading-assumed-knowledge">Assumed Knowledge</h3>
<p>This tutorial is designed to be beginner-friendly, but I do make a few assumptions about what you already know:</p>
<ul>
<li>Fundamentals of TypeScript</li>
<li>Basics of NestJS</li>
<li>Docker</li>
</ul>
<p>If you're not familiar with these, don't fret! I've got you covered. This tutorial will guide you through everything you need to know. </p>
<p>But here are some more resources if you'd like to learn more:</p>
<ul>
<li>For a deeper dive into NestJS, feel free to explore the <a target="_blank" href="https://docs.nestjs.com/">official NestJS documentation</a>.</li>
<li>To learn more about Docker, here's a <a target="_blank" href="https://www.freecodecamp.org/news/the-docker-handbook/">full handbook for beginners</a>.</li>
<li>And for more info on TypeScript, here's a <a target="_blank" href="https://www.freecodecamp.org/news/learn-typescript-with-this-crash-course/">helpful crash course</a>.</li>
</ul>
<h2 id="heading-development-environment">Development Environment</h2>
<h3 id="heading-tools-and-technologies">Tools and Technologies</h3>
<p>In this tutorial, we'll use the following tools:</p>
<ul>
<li><a target="_blank" href="https://nodejs.org/en/download/">Node.js</a> – Our runtime environment</li>
<li><a target="_blank" href="https://www.docker.com/get-started/">Docker</a> – For containerizing our database</li>
<li><a target="_blank" href="https://code.visualstudio.com/Download">Visual Studio Code</a> – Our code editor</li>
<li><a target="_blank" href="https://www.postgresql.org/download/">PostgreSQL</a> – Our database</li>
<li><a target="_blank" href="https://docs.nestjs.com/">NestJS</a> – Our Node.js framework</li>
</ul>
<p><strong>Note:</strong> Don't forget to install the Prisma extension for Visual Studio Code. It enhances your coding experience by highlighting Prisma-specific syntax and keywords.</p>
<h2 id="heading-how-to-set-up-the-nestjs-project">How to Set Up the NestJS Project</h2>
<p>NestJS is a progressive Node.js framework that comes with a plethora of advantages, including a powerful Command Line Interface (CLI). This CLI simplifies the process of creating a new NestJS application, making it easy to start a new project anytime, anywhere.</p>
<p>One of the key benefits of NestJS is its rich set of built-in functionalities that significantly streamline the development process, making your life as a developer much easier.</p>
<p>Let's begin by installing the NestJS CLI on your system:</p>
<pre><code class="lang-bash">npm i -g @nestjs/cli
</code></pre>
<p>With the NestJS CLI installed, you're all set to whip up our recipe project. The CLI streamlines the creation of a new NestJS application, making it simple to get started. </p>
<p>To spin up a new project, execute the following command:</p>
<pre><code class="lang-bash">nest new recipe
</code></pre>
<p>After running this command, you'll encounter a prompt like the one you see below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/Settting-nest.png" alt="Nest CLI Package Manager Prompt" width="600" height="400" loading="lazy">
<em>The Nest CLI prompting for a package manager selection during project setup.</em></p>
<p>As illustrated in the image, the Nest CLI will prompt you to select a package manager. For this project, we'll opt for <code>npm</code>. Once you've made your selection, the CLI will proceed with the project setup, and you'll see a series of operations being performed in your terminal.</p>
<p>Now you can open you project in VSCode (or the editor of your choice). You should see the following files:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/After-setting-up-nejst.png" alt="Nest CLI Package Manager Prompt" width="600" height="400" loading="lazy">
<em>The folder structure of the project after it has been created using Nest CLI.</em></p>
<p>Let break down the project structure:</p>
<table>
<thead>
<tr>
<th>Directory/File</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>recipe/</code></td>
<td>Root directory of the project.</td>
</tr>
<tr>
<td><code>├── node_modules/</code></td>
<td>Contains all the npm packages required for the project.</td>
</tr>
<tr>
<td><code>├── src/</code></td>
<td>Contains the source code of the application.</td>
</tr>
<tr>
<td><code>│ ├── app.controller.spec.ts</code></td>
<td>Contains the tests for <code>app.controller.ts</code>.</td>
</tr>
<tr>
<td><code>│ ├── app.controller.ts</code></td>
<td>Contains a basic controller with a single route.</td>
</tr>
<tr>
<td><code>│ ├── app.module.ts</code></td>
<td>The root module of the application.</td>
</tr>
<tr>
<td><code>│ ├── app.service.ts</code></td>
<td>Contains the services used by <code>app.controller.ts</code>.</td>
</tr>
<tr>
<td><code>│ └── main.ts</code></td>
<td>The entry point of the application.</td>
</tr>
<tr>
<td><code>├── test/</code></td>
<td>Contains the end-to-end tests for the application.</td>
</tr>
<tr>
<td><code>│ ├── app.e2e-spec.ts</code></td>
<td>Contains the end-to-end tests for <code>app.controller.ts</code>.</td>
</tr>
<tr>
<td><code>│ └── jest-e2e.json</code></td>
<td>Contains the configuration for the end-to-end tests.</td>
</tr>
<tr>
<td><code>├── README.md</code></td>
<td>The readme file for the project.</td>
</tr>
<tr>
<td><code>├── nest-cli.json</code></td>
<td>Contains the configuration for the NestJS CLI.</td>
</tr>
<tr>
<td><code>├── package-lock.json</code></td>
<td>Contains the exact versions of the npm packages used in the project.</td>
</tr>
<tr>
<td><code>├── package.json</code></td>
<td>Lists the npm packages required for the project.</td>
</tr>
<tr>
<td><code>└── tsconfig.build.json</code></td>
<td>Contains the TypeScript compiler options for the build.</td>
</tr>
</tbody>
</table>

<p>The <code>src</code> directory is the nerve center of our application, hosting the bulk of our codebase. The NestJS CLI has already set the stage for us with several key files:</p>
<ul>
<li><code>src/app.module.ts</code>: This is the root module of our application, serving as the main junction for all other modules.</li>
<li><code>src/app.controller.ts</code>: This file houses a basic controller with a single route: <code>/.</code> When accessed, this route will return a simple 'Hello World!' message.</li>
<li><code>src/main.ts</code>: This is the gateway to our application. It's tasked with bootstrapping and launching the NestJS application.</li>
</ul>
<p>To start your project and see the 'Hello World!' message in action, execute the following command:</p>
<pre><code class="lang-bash">npm run start:dev
</code></pre>
<p>This command triggers a live-reload development server. It vigilantly monitors your files, and if it spots any modifications, it automatically recompile your code and refreshes the server. This ensures that you can see your changes in real-time, eliminating the need for manual restarts.</p>
<p>To verify that your server is operational, head over to <code>http://localhost:3000/</code> in your web browser or Postman. You should be welcomed by a minimalist page showcasing the message <code>Hello World</code>. This is your application's default landing page, a pristine canvas awaiting your creative touch.</p>
<h2 id="heading-how-to-create-a-postgresql-instance-with-docker">How to Create a PostgreSQL Instance with Docker</h2>
<p>To store our recipes REST API, we'll use a PostgreSQL database. Docker will help us containerize this database, ensuring a smooth setup and execution, regardless of the environment.</p>
<p>First, ensure Docker is installed on your system. If not, follow the instructions <a target="_blank" href="https://www.docker.com/get-started">here</a>.</p>
<p>Next, you'll need to create a <code>docker-compose.yml</code> file.</p>
<p>Open the terminal and run the following command:</p>
<pre><code class="lang-bash">touch docker-compose.yml
</code></pre>
<p>This command creates a new <code>docker-compose.yml</code> file in your project's root directory.</p>
<p>Open the <code>docker-compose.yml</code> file and add the following code:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># docker-compose.yml</span>

version: <span class="hljs-string">'3.8'</span>
services:
  postgres:
    image: postgres:13.5
    restart: always
    environment:
      - POSTGRES_USER=recipe
      - POSTGRES_PASSWORD=RecipePassword
    volumes:
      - postgres:/var/lib/postgresql/data
    ports:
      - <span class="hljs-string">'5432:5432'</span>
volumes:
  postgres:
</code></pre>
<p>Here's a quick breakdown of this configuration:</p>
<ul>
<li><code>image: postgres:13.5</code>: Specifies the Docker image for the PostgreSQL database.</li>
<li><code>restart: always</code>: Ensures the container restarts if it stops.</li>
<li><code>environment</code>: Sets the username and password for the database.</li>
<li><code>volumes</code>: Mounts a volume to persist database data, even if the container is stopped or removed.</li>
<li><code>ports</code>: Exposes port <code>5432</code> on both the host machine and the container for database access.</li>
</ul>
<p>Note: If you wish to use a different port, simply change the host machine port. For example, to use port <code>5433</code>, modify the <code>ports</code> section as follows:</p>
<pre><code class="lang-bash">ports:
  - <span class="hljs-string">'5444:5432'</span>
</code></pre>
<p>Note: Before proceeding, ensure port <code>5432</code> is free on your machine. To fire up the PostgreSQL container, execute the following command in your project's root directory (and also make sure you have open the docker desktop app and it is running):</p>
<pre><code class="lang-bash">docker-compose up
</code></pre>
<p>This command spins up the PostgreSQL container and makes it accessible on port <code>5432</code> of your machine. If all goes according to plan, you should see output similar to this:</p>
<pre><code class="lang-bash">...
 | PostgreSQL init process complete; ready <span class="hljs-keyword">for</span> start up.
postgres-1  |
postgres-1  | 2024-01-12 14:59:33.519 UTC [1] LOG:  starting PostgreSQL 13.5 (Debian 13.5-1.pgdg110+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit
postgres-1  | 2024-01-12 14:59:33.520 UTC [1] LOG:  listening on IPv4 address <span class="hljs-string">"0.0.0.0"</span>, port 5432
postgres-1  | 2024-01-12 14:59:33.520 UTC [1] LOG:  listening on IPv6 address <span class="hljs-string">"::"</span>, port 5432
postgres-1  | 2024-01-12 14:59:33.526 UTC [1] LOG:  listening on Unix socket <span class="hljs-string">"/var/run/postgresql/.s.PGSQL.5432"</span>
postgres-1  | 2024-01-12 14:59:33.533 UTC [62] LOG:  database system was shut down at 2024-01-12 14:59:33 UTC
postgres-1  | 2024-01-12 14:59:33.550 UTC [1] LOG:  database system is ready to accept connections
</code></pre>
<p>Remember, if you've changed the port number, the output will reflect your chosen port.</p>
<p>If the port is already in use, you'll encounter an error message like this:</p>
<pre><code class="lang-bash">Error starting userland proxy: listen tcp 0.0.0.0:5432: <span class="hljs-built_in">bind</span>: address already <span class="hljs-keyword">in</span> use
</code></pre>
<p>In such a case, free up the port or choose a different one in your <code>docker-compose.yml</code> file.</p>
<p>Note: if you close the terminal window, it will also stop the container. To prevent this, you can run the container in detached mode. This mode allows the container to run indefinitely in the background. </p>
<p>To do this, add a <code>-d</code> option at the end of the command, like so:</p>
<pre><code class="lang-bash">docker-compose up -d
</code></pre>
<p>To stop the container, use the following command:</p>
<pre><code class="lang-bash">docker-compose down
</code></pre>
<p>Congratulations 🎉. You now have your own PostgreSQL database to play around with.</p>
<h2 id="heading-how-to-set-up-prisma">How to Set Up Prisma</h2>
<p>Now that we have our PostgreSQL database up and running, we're ready to set up Prisma. Prisma is an open-source database toolkit that makes it easy to reason about your data and how you interact with it.</p>
<p>Prisma is a powerful tool that offers a wide range of features, including:</p>
<ul>
<li><strong>Database Migrations</strong>: Prisma makes it easy to evolve your database schema over time, without losing any data.</li>
<li><strong>Database Seeding</strong>: Prisma allows you to seed your database with test data.</li>
<li><strong>Database Access</strong>: Prisma provides a powerful API for accessing your database.</li>
<li><strong>Database Schema Management</strong>: Prisma allows you to define your database schema using the Prisma Schema Language.</li>
<li><strong>Database Querying</strong>: Prisma provides a powerful API for querying your database.</li>
<li><strong>Database Relationships</strong>: Prisma allows you to define relationships between your database tables.</li>
</ul>
<p>You can learn more about Prisma <a target="_blank" href="https://www.prisma.io/">here</a>.</p>
<h3 id="heading-how-to-initialize-prisma">How to Initialize Prisma</h3>
<p>To get started with Prisma, we'll need to install the Prisma CLI. This CLI allows us to interact with our database, making it easy to perform database migrations, seeding, and more.</p>
<p>To install the Prisma CLI, execute the following command:</p>
<pre><code class="lang-bash">
npm install prisma -D
</code></pre>
<p>This command installs the Prisma CLI as a development dependency in your project. The <code>-D</code> flag tells npm to install the package as a development dependency.</p>
<p>Next, initialize Prisma in your project by executing the following command:</p>
<pre><code class="lang-bash">
npx prisma init
</code></pre>
<p>This will create a new <code>prisma</code> directory with a <code>schema.prisma</code> file. This is the main configuration file that contains your database schema. This command also creates a <code>.env</code> file inside your project.</p>
<h3 id="heading-how-to-set-your-environment-variable">How to Set Your Environment Variable</h3>
<p>The <code>.env</code> file contains the environment variables required to connect to your database. Open this file and replace the contents with the following:</p>
<pre><code class="lang-bash">
DATABASE_URL=<span class="hljs-string">"postgres://recipe:RecipePassword@localhost:5444/recipe"</span>
</code></pre>
<p>Note: If you changed the port number in your <code>docker-compose.yml</code> file, ensure you update the port number in the <code>DATABASE_URL</code> environment variable with the port number you used.</p>
<p>This environment variable contains the connection string for your database. It's used by Prisma to connect to your database in the docker container.</p>
<h3 id="heading-understanding-the-prisma-schema">Understanding the Prisma Schema</h3>
<p>The <code>schema.prisma</code> file contains the schema for your database. It's written in the Prisma Schema Language, a declarative language for defining your database schema. The <code>prisma/schema.prisma</code> file is the main configuration file for your Prisma setup. It defines your database connection and the Prisma Client generator.</p>
<pre><code class="lang-ts">
<span class="hljs-comment">// prisma/schema.prisma</span>

generator client {
  provider = <span class="hljs-string">"prisma-client-js"</span>
}

datasource db {
  provider = <span class="hljs-string">"postgresql"</span>
  url      = env(<span class="hljs-string">"DATABASE_URL"</span>)
}
</code></pre>
<p>This file is written in the Prisma Schema Language, which is a language that Prisma uses to define your database schema. The <code>schema.prisma</code> file has three main components:</p>
<ul>
<li><strong>Generator</strong>: This section defines the Prisma Client generator. The Prisma Client generator is responsible for generating the Prisma Client, a powerful API for accessing your database.</li>
<li><strong>Datasource</strong>: This section defines the database connection. It specifies the database provider and the connection string. It use <code>DATABASE_URL</code> environment variable to connect to your database.</li>
<li><strong>Model</strong>: This section defines the database schema. It specifies the database tables and their fields.</li>
</ul>
<h2 id="heading-how-to-model-the-data">How to Model the Data</h2>
<p>Now that we have set up our Prisma, we're ready to model our data. We'll be building a recipe management system, so we'll need to define a <code>Recipe</code> model. This model will have various fields.</p>
<p>Open the <code>schema.prisma</code> file and add the following code:</p>
<pre><code class="lang-ts">
 <span class="hljs-comment">// prisma/schema.prisma</span>
 <span class="hljs-comment">// ...</span>
model Recipe {
  id           Int      <span class="hljs-meta">@id</span> <span class="hljs-meta">@default</span>(autoincrement())
  title        <span class="hljs-built_in">String</span>   <span class="hljs-meta">@unique</span>
  description  <span class="hljs-built_in">String</span>?
  ingredients  <span class="hljs-built_in">String</span>
  instructions <span class="hljs-built_in">String</span>
  createdAt    DateTime <span class="hljs-meta">@default</span>(now())
  updatedAt    DateTime <span class="hljs-meta">@updatedAt</span>
}
</code></pre>
<p>Here's a quick breakdown of this model:</p>
<ul>
<li><code>id</code>: This is the primary key of the <code>Recipe</code> model. It's an auto-incrementing integer that uniquely identifies each recipe. It has the <code>@id</code> attribute, which tells Prisma that this field is the primary key. It also has the <code>@default(autoincrement())</code> attribute, which tells Prisma to auto-increment this field.</li>
<li><code>title</code>: This is the title of the recipe. It's a unique string that's used to identify the recipe.</li>
<li><code>description</code>: This is the description of the recipe. It's an optional string that describes the recipe.</li>
<li><code>ingredients</code>: This is the list of ingredients used in the recipe. It's a string that contains a comma-separated list of ingredients.</li>
<li><code>instructions</code>: This is the list of instructions for preparing the recipe. It's a string that contains a comma-separated list of instructions.</li>
<li><code>createdAt</code>: This is the date and time the recipe was created. It's set to the current date and time by default. It has the <code>@default(now())</code> attribute, which tells Prisma to set this field to the current date and time by default.</li>
<li><code>updatedAt</code>: This is the date and time the recipe was last updated. It's set to the current date and time by default.</li>
</ul>
<h2 id="heading-how-to-migrate-the-database">How to Migrate the Database</h2>
<p>Now that we've defined our database schema, we're ready to migrate our database. This will create the database tables and fields defined in our <code>schema.prisma</code> file.</p>
<p>To migrate your database, execute the following command:</p>
<pre><code class="lang-bash">npx prisma migrate dev --name init
</code></pre>
<p>This command will do three things:</p>
<p><strong>Save the migration</strong>: Prisma Migrate will take a snapshot of your schema and figure out the SQL commands necessary to carry out the migration. Prisma will save the migration file containing the SQL commands to the newly created <code>prisma/migrations</code> folder.</p>
<p><strong>Execute the migration</strong>: Prisma Migrate will execute the SQL commands in the migration file, creating the database tables and fields defined in your <code>schema.prisma</code> file.</p>
<p><strong>Generate Prisma Client</strong>: Prisma will generate Prisma Client based on your latest schema. Since you did not have the Client library installed, the CLI will install it for you as well. You should see the <code>@prisma/client</code> package inside dependencies in your package.json file. </p>
<p>Prisma Client is a TypeScript query builder auto-generated from your Prisma schema. It is tailored to your Prisma schema and will be used to send queries to the database.</p>
<p>If all goes according to plan, you should see output similar to this:</p>
<pre><code class="lang-bash">The following migration(s) have been created and applied from new schema changes:

migrations/
  └─ 20220528101323_init/
    └─ migration.sql

Your database is now <span class="hljs-keyword">in</span> sync with your schema.
...
✔ Generated Prisma Client (3.14.0 | library) to ./node_modules/@prisma/client <span class="hljs-keyword">in</span> 31ms
</code></pre>
<p>Check the generated migration file to get an idea about what Prisma Migrate is doing behind the scenes:</p>
<pre><code class="lang-bash">-- prisma/migrations/20220528101323_init/migration.sql

CREATE TABLE <span class="hljs-string">"Recipe"</span> (
    <span class="hljs-string">"id"</span> SERIAL NOT NULL,
    <span class="hljs-string">"title"</span> TEXT NOT NULL,
    <span class="hljs-string">"description"</span> TEXT,
    <span class="hljs-string">"ingredients"</span> TEXT NOT NULL,
    <span class="hljs-string">"instructions"</span> TEXT NOT NULL,
    <span class="hljs-string">"createdAt"</span> TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    <span class="hljs-string">"updatedAt"</span> TIMESTAMP(3) NOT NULL,

    CONSTRAINT <span class="hljs-string">"Recipe_pkey"</span> PRIMARY KEY (<span class="hljs-string">"id"</span>)
);

-- CreateIndex
CREATE UNIQUE INDEX <span class="hljs-string">"Recipe_title_key"</span> ON <span class="hljs-string">"Recipe"</span>(<span class="hljs-string">"title"</span>);
</code></pre>
<p>This migration file contains the SQL commands necessary to create the <code>Recipe</code> table. It also contains the SQL commands necessary to create the <code>title</code> field, which is a unique field. This ensures that the <code>title</code> field is unique, preventing duplicate recipes from being created.</p>
<h2 id="heading-how-to-seed-the-database">How to Seed the Database</h2>
<p>Now that we've migrated our database, we're ready to seed it with some test data. This will allow us to test our application without having to manually create recipes.</p>
<p>Firstly, create a seed file called <code>prisma/seed.ts</code>. This file will contain the dummy data and queries needed to seed your database.</p>
<p>Open the terminal and run the following command:</p>
<pre><code class="lang-bash">touch prisma/seed.ts
</code></pre>
<p>This command creates a new <code>prisma/seed.ts</code> file in your project's root directory.</p>
<p>Next, populate this file with the following code:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// prisma/seed.ts</span>
<span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@prisma/client'</span>;

<span class="hljs-comment">// initialize Prisma Client</span>
<span class="hljs-keyword">const</span> prisma = <span class="hljs-keyword">new</span> PrismaClient();

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// create two dummy recipes</span>
  <span class="hljs-keyword">const</span> recipe1 = <span class="hljs-keyword">await</span> prisma.recipe.upsert({
    where: { title: <span class="hljs-string">'Spaghetti Bolognese'</span> },
    update: {},
    create: {
      title: <span class="hljs-string">'Spaghetti Bolognese'</span>,
      description: <span class="hljs-string">'A classic Italian dish'</span>,
      ingredients:
        <span class="hljs-string">'Spaghetti, minced beef, 
        tomato sauce, onions, garlic, olive oil, salt, pepper'</span>,
      instructions:
        <span class="hljs-string">'1. Cook the spaghetti. 2. Fry the minced beef. 3.
        Add the tomato sauce to the beef.
        4. Serve the spaghetti with the sauce.'</span>
    }
  });

  <span class="hljs-keyword">const</span> recipe2 = <span class="hljs-keyword">await</span> prisma.recipe.upsert({
    where: { title: <span class="hljs-string">'Chicken Curry'</span> },
    update: {},
    create: {
      title: <span class="hljs-string">'Chicken Curry'</span>,
      description: <span class="hljs-string">'A spicy Indian dish'</span>,
      ingredients:
        <span class="hljs-string">'Chicken, curry powder, onions, garlic, 
        coconut milk, olive oil, salt, pepper'</span>,
      instructions:
        <span class="hljs-string">'1. Fry the chicken. 2. Add the curry powder to the
        chicken. 3. Add the coconut milk.
        4. Serve the curry with rice.'</span>
    }
  });

  <span class="hljs-built_in">console</span>.log({ recipe1, recipe2 });
}

<span class="hljs-comment">// execute the main function</span>
main()
  .catch(<span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> {
    <span class="hljs-built_in">console</span>.error(e);
    process.exit(<span class="hljs-number">1</span>);
  })
  .finally(<span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// close Prisma Client at the end</span>
    <span class="hljs-keyword">await</span> prisma.$disconnect();
  });
</code></pre>
<p>This file contains the dummy data and queries needed to seed your database. Let's break it down:</p>
<ul>
<li><code>import { PrismaClient } from '@prisma/client';</code>: This imports the Prisma Client, which is used to send queries to the database.</li>
<li><code>const prisma = new PrismaClient();</code>: This initializes the Prisma Client, allowing us to send queries to the database.</li>
<li><code>async function main() { ... }</code>: This is the main function that contains the dummy data and queries needed to seed your database.</li>
<li><code>const recipe1 = await prisma.recipe.upsert({ ... });</code>: This creates a new recipe. It uses the <code>upsert</code> method, which creates a new recipe if it doesn't exist, or updates the existing recipe if it does.</li>
<li><code>const recipe2 = await prisma.recipe.upsert({ ... });</code>: This creates a new recipe. It uses the <code>upsert</code> method, which creates a new recipe if it doesn't exist, or updates the existing recipe if it does.</li>
<li><code>console.log({ recipe1, recipe2 });</code>: This logs the newly created recipes to the console.</li>
<li><code>main().catch((e) =&gt; { ... });</code>: This executes the main function and catches any errors that occur.</li>
<li><code>await prisma.$disconnect();</code>: This closes the Prisma Client at the end.</li>
</ul>
<p>Now before we can seed our database, we need add a script to our <code>package.json</code> file. Open the <code>package.json</code> file and add the following script:</p>
<pre><code class="lang-json">

<span class="hljs-comment">// package.json</span>

<span class="hljs-comment">// ...</span>
  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-comment">// ...</span>
  },
  <span class="hljs-string">"dependencies"</span>: {
    <span class="hljs-comment">// ...</span>
  },
  <span class="hljs-string">"devDependencies"</span>: {
    <span class="hljs-comment">// ...</span>
  },
  <span class="hljs-string">"jest"</span>: {
    <span class="hljs-comment">// ...</span>
  },
  <span class="hljs-comment">// pasting the prisma script here</span>
  <span class="hljs-string">"prisma"</span>: {
    <span class="hljs-attr">"seed"</span>: <span class="hljs-string">"ts-node prisma/seed.ts"</span>
  }
</code></pre>
<p>The seed command will execute the <code>prisma/seed.ts</code> script that you previously defined. This command should work automatically because ts-node is already installed as a dev dependency in your <code>package.json</code>.</p>
<p>Now that we've defined our seed script, we're ready to seed the database. To seed your database, execute the following command:</p>
<pre><code class="lang-bash">npx prisma db seed
</code></pre>
<p>This command will seed your database with the dummy data defined in your <code>prisma/seed.ts</code> file. If all goes according to plan, you should see output similar to this:</p>
<pre><code class="lang-ts">Running seed command <span class="hljs-string">`ts-node prisma/seed.ts`</span> ...
{
  recipe1: {
    id: <span class="hljs-number">1</span>,
    title: <span class="hljs-string">'Spaghetti Bolognese'</span>,
    description: <span class="hljs-string">'A classic Italian dish'</span>,
    ingredients: <span class="hljs-string">'Spaghetti, minced beef, tomato sauce, onions, garlic, olive oil, salt, pepper'</span>,
    instructions: <span class="hljs-string">'1. Cook the spaghetti. 2. Fry the minced beef. 3. Add the tomato sauce to the beef. 4. Serve the spaghetti with the sauce.'</span>,
    createdAt: <span class="hljs-number">2024</span><span class="hljs-number">-01</span><span class="hljs-number">-12</span>T16:<span class="hljs-number">21</span>:<span class="hljs-number">09.133</span>Z,
    updatedAt: <span class="hljs-number">2024</span><span class="hljs-number">-01</span><span class="hljs-number">-12</span>T16:<span class="hljs-number">21</span>:<span class="hljs-number">09.133</span>Z
  },
  recipe2: {
    id: <span class="hljs-number">2</span>,
    title: <span class="hljs-string">'Chicken Curry'</span>,
    description: <span class="hljs-string">'A spicy Indian dish'</span>,
    ingredients: <span class="hljs-string">'Chicken, curry powder, onions, garlic, coconut milk, olive oil, salt, pepper'</span>,
    instructions: <span class="hljs-string">'1. Fry the chicken. 2. Add the curry powder to the chicken. 3. Add the coconut milk. 4. Serve the curry with rice.'</span>,
    createdAt: <span class="hljs-number">2024</span><span class="hljs-number">-01</span><span class="hljs-number">-12</span>T16:<span class="hljs-number">21</span>:<span class="hljs-number">09.155</span>Z,
    updatedAt: <span class="hljs-number">2024</span><span class="hljs-number">-01</span><span class="hljs-number">-12</span>T16:<span class="hljs-number">21</span>:<span class="hljs-number">09.155</span>Z
  }
}

The seed command has been executed.
</code></pre>
<p>Congratulations 🎉. You now have a fully functional database with dummy data.</p>
<h2 id="heading-how-to-create-a-prisma-service">How to Create a Prisma Service</h2>
<p>Now that we've set up Prisma, we're ready to create a Prisma service. This service will act as a wrapper around the Prisma Client, making it easy to send queries to the database.</p>
<p>The Nest CLI gives you an easy way to generate modules and services directly from the CLI. Run the following command in your terminal:</p>
<pre><code class="lang-bash">
npx nest generate module prisma
npx nest generate service prisma
</code></pre>
<p>Note that the <code>generate</code> command can be shortened to <code>g</code>. So, you can also run the following command:</p>
<pre><code class="lang-bash">
npx nest g module prisma
npx nest g service prisma
</code></pre>
<p>This command generates a new module called <code>prisma</code> and a new service called <code>prisma</code>. It also imports the <code>PrismaModule</code> into the <code>AppModule</code>.</p>
<p>So you should see something like this:</p>
<pre><code class="lang-bash">
  src/prisma/prisma.service.spec.ts
  src/prisma/prisma.service.ts
  src/prisma/prisma.module.ts
</code></pre>
<p>Note: In some cases, you may need to restart your server for the changes to take effect.</p>
<p>Next, open the <code>prisma.service.ts</code> file and replace the contents with the following:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/prisma/prisma.service.ts</span>

<span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@prisma/client'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> PrismaService <span class="hljs-keyword">extends</span> PrismaClient {}
</code></pre>
<p>This service is a wrapper around the Prisma Client, making it easy to send queries to the database. It's also a NestJS provider, which means it can be injected into other modules.</p>
<p>Next, open the <code>prisma.module.ts</code> file and replace the contents with the following:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/prisma/prisma.module.ts</span>
<span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { PrismaService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./prisma.service'</span>;

<span class="hljs-meta">@Module</span>({
  providers: [PrismaService],
  <span class="hljs-built_in">exports</span>: [PrismaService]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> PrismaModule {}
</code></pre>
<p><strong>Note:</strong> The <code>PrismaModule</code> is a NestJS module that imports the <code>PrismaService</code>, making it readily available for use across other modules in your application. This setup allows seamless integration of the Prisma service throughout your project.</p>
<p>Congratulations 🎉! You've successfully set up your Prisma service.</p>
<p>Before we dive into writing our application logic, let's set up Swagger. Swagger is an industry-standard tool for designing, building, and documenting RESTful APIs. It empowers developers to create elegant and comprehensive API documentation effortlessly.</p>
<h2 id="heading-how-to-set-up-swagger">How to Set Up Swagger</h2>
<p>To configure Swagger, we'll leverage the <code>@nestjs/swagger</code> package. This package offers a suite of decorators and methods specifically designed to generate Swagger documentation.</p>
<p>To install this package, run the following command:</p>
<pre><code class="lang-bash">npm install --save @nestjs/swagger swagger-ui-express
</code></pre>
<p>This command adds the <code>@nestjs/swagger</code> package as a dependency in your project. It also installs the <code>swagger-ui-express</code> package, which serves the Swagger UI.</p>
<p>Next, navigate to the <code>main.ts</code> file and append the following code:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/main.ts</span>

<span class="hljs-keyword">import</span> { NestFactory } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/core'</span>;
<span class="hljs-keyword">import</span> { AppModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.module'</span>;
<span class="hljs-keyword">import</span> { SwaggerModule, DocumentBuilder } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/swagger'</span>;

<span class="hljs-comment">// Define the bootstrap function</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bootstrap</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Create a NestJS application instance by passing the AppModule to the NestFactory</span>
  <span class="hljs-keyword">const</span> app = <span class="hljs-keyword">await</span> NestFactory.create(AppModule);

  <span class="hljs-comment">// Use DocumentBuilder to create a new Swagger document configuration</span>
  <span class="hljs-keyword">const</span> config = <span class="hljs-keyword">new</span> DocumentBuilder()
    .setTitle(<span class="hljs-string">'Recipes API'</span>) <span class="hljs-comment">// Set the title of the API</span>
    .setDescription(<span class="hljs-string">'Recipes API description'</span>) <span class="hljs-comment">// Set the description of the API</span>
    .setVersion(<span class="hljs-string">'0.1'</span>) <span class="hljs-comment">// Set the version of the API</span>
    .build(); <span class="hljs-comment">// Build the document</span>

  <span class="hljs-comment">// Create a Swagger document using the application instance and the document configuration</span>
  <span class="hljs-keyword">const</span> <span class="hljs-built_in">document</span> = SwaggerModule.createDocument(app, config);

  <span class="hljs-comment">// Setup Swagger module with the application instance and the Swagger document</span>
  SwaggerModule.setup(<span class="hljs-string">'api'</span>, app, <span class="hljs-built_in">document</span>);

  <span class="hljs-comment">// Start the application and listen for requests on port 3000</span>
  <span class="hljs-keyword">await</span> app.listen(<span class="hljs-number">3000</span>);
}

<span class="hljs-comment">// Call the bootstrap function to start the application</span>
bootstrap();
</code></pre>
<p>This code initializes Swagger and generates the Swagger documentation. Let's break it down:</p>
<ul>
<li><code>const config = new DocumentBuilder() ... .build();</code>: This creates a new Swagger document builder. It sets the title, description, and version of the Swagger document. It also builds the Swagger document.</li>
<li><code>const document = SwaggerModule.createDocument(app, config);</code>: This creates a new Swagger document. It uses the Swagger document builder to generate the Swagger document.</li>
<li><code>SwaggerModule.setup('api', app, document);</code>: This sets up the Swagger UI. It uses the Swagger document to generate the Swagger UI.</li>
</ul>
<p>While the application is running, open your browser and navigate to <code>http://localhost:3000/api</code>. You should see the Swagger UI.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/Swager-first-look.png" alt="Swagger UI " width="600" height="400" loading="lazy">
<em>The initial view of the Swagger UI after successful setup.</em></p>
<p>Now that we've set up Swagger, we're ready to start building our REST API.</p>
<h2 id="heading-how-to-implement-crud-operations-for-the-recipe-model">How to Implement CRUD Operations for the Recipe Model</h2>
<p>In this section we'll implement the CRUD operations for the <code>Recipe</code> model. We'll start by generating the REST resources for the <code>Recipe</code> model. Then we'll add the Prisma Client to the <code>Recipe</code> module. Finally, we'll implement the CRUD operations for the <code>Recipe</code> model.</p>
<h3 id="heading-how-to-generate-rest-resources-with-nestjs-cli">How to Generate REST Resources with NestJS CLI</h3>
<p>Before we can implement the CRUD operations for the <code>Recipe</code> model, we need to generate the REST resources for the <code>Recipe</code> model. This will create the boilerplate code for the <code>Recipe</code> module, controller, service, and DTOs. </p>
<p>To generate the REST resources for the <code>Recipe</code> model, execute the following command:</p>
<pre><code class="lang-bash">
npx nest generate resource recipe
</code></pre>
<p>And it will ask you what type of API you want to generate. So now we will select the <code>REST API</code> .</p>
<p>Check out the below image for reference:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/Generating-CRUD.png" alt="REST API  " width="600" height="400" loading="lazy">
<em>Selecting REST API when creating the CRUD operations using the Nest CLI</em></p>
<p>This command will generate the following files:</p>
<pre><code class="lang-bash">
CREATE src/recipe/recipe.controller.ts (959 bytes)
CREATE src/recipe/recipe.controller.spec.ts (596 bytes)
CREATE src/recipe/recipe.module.ts (264 bytes)
CREATE src/recipe/recipe.service.ts (661 bytes)
CREATE src/recipe/recipe.service.spec.ts (478 bytes)
CREATE src/recipe/dto/create-recipe.dto.ts (33 bytes)
CREATE src/recipe/dto/update-recipe.dto.ts (176 bytes)
CREATE src/recipe/entities/recipe.entity.ts (24 bytes)
UPDATE src/app.module.ts (385 bytes)
</code></pre>
<p>If you open the Swagger API page again, you should see something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/swagger-pplo--after-crating-crud.png" alt="SWagger UI  " width="600" height="400" loading="lazy">
<em>The Swagger UI displaying the newly created CRUD operations.</em></p>
<p>The swagger page now has a new section called <code>Recipe API</code> . This section contains the REST resources for the <code>Recipe</code> model.</p>
<p>Now when you open Swagger you will see something like this:</p>
<ul>
<li><code>POST /recipes</code>: Create a new recipe.</li>
<li><code>GET /recipes</code>: Retrieve all recipes.</li>
<li><code>GET /recipes/{id}</code>: Retrieve a specific recipe by its ID.</li>
<li><code>PATCH /recipes/{id}</code>: Update a specific recipe by its ID.</li>
<li><code>DELETE /recipes/{id}</code>: Delete a specific recipe by its ID.</li>
</ul>
<h3 id="heading-how-to-add-prismaclient-to-the-recipe-module">How to Add <code>PrismaClient</code> to the Recipe Module</h3>
<p>Now that we've generated the REST resources for the <code>Recipe</code> model, we're ready to add the Prisma Client to the <code>Recipe</code> module. This will allow us to send queries to the database.</p>
<p>Firstly, open the <code>recipe.module.ts</code> file and add the following code:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.module.ts</span>

<span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { RecipeService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./recipe.service'</span>;
<span class="hljs-keyword">import</span> { RecipeController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./recipe.controller'</span>;
<span class="hljs-keyword">import</span> { PrismaModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'../prisma/prisma.module'</span>;

<span class="hljs-meta">@Module</span>({
  imports: [PrismaModule],
  controllers: [RecipeController],
  providers: [RecipeService]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> RecipeModule {}
</code></pre>
<p>So now we have imported the <code>PrismaModule</code> and added it to the <code>imports</code> array. This will make the <code>PrismaService</code> available to the <code>RecipeService</code>.</p>
<p>Next, open the <code>recipe.service.ts</code> file and add the following code:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.service.ts</span>
<span class="hljs-keyword">import</span> { Body, Injectable, Post } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { CreateRecipeDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/create--recipe.dto'</span>;
<span class="hljs-keyword">import</span> { UpdateRecipeDto } <span class="hljs-keyword">from</span> <span class="hljs-string">'./dto/update--recipe.dto'</span>;
<span class="hljs-keyword">import</span> { PrismaService } <span class="hljs-keyword">from</span> <span class="hljs-string">'src/prisma/prisma.service'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> RecipesService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> prisma: PrismaService</span>) {}

  <span class="hljs-comment">//  rest of the code</span>
}
</code></pre>
<p>So now we have defined the <code>prisma</code> service as a private property of the <code>RecipeService</code> class. This will allow us to access the <code>PrismaService</code> from within the <code>RecipeService</code> class. So now we use the <code>prisma</code> service to perform the CRUD operations.</p>
<p>Sine we have defined the service for the Recipe model, we're ready to implement the CRUD operations for the Recipe model.</p>
<h3 id="heading-how-to-define-the-get-recipes-endpoint">How to Define the <code>GET /recipes</code> Endpoint</h3>
<p>Let's kickstart our journey into crafting API endpoints by defining the <code>GET /recipes</code> endpoint. This endpoint will serve as a gateway to fetch all the recipes stored in our database.</p>
<p>In your <code>recipes.controller.ts</code> file, you'll find a method named <code>findAll</code>. This method, as the name suggests, is responsible for fetching all the recipes. Here's how we'll define it:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.controller.ts</span>

<span class="hljs-comment">// Other code...</span>

<span class="hljs-meta">@Get</span>()
<span class="hljs-keyword">async</span> findAll() {
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.recipeService.findAll();
}

<span class="hljs-comment">// Other code...</span>
</code></pre>
<p>In the above code:</p>
<ul>
<li>The <code>@Get()</code> decorator maps the <code>findAll</code> method to the <code>GET /recipes</code> endpoint.</li>
<li>The <code>findAll</code> method invokes the <code>findAll</code> method of the <code>recipeService</code>, which retrieves all the recipes from the database.</li>
</ul>
<p>As we've previously seen, the <code>Controller</code> is the heart of our application's logic. In this context, we're aiming to implement a <code>findAll</code> method that fetches all recipes from our database. To accomplish this, we'll harness the power of Prisma's services within our <code>recipe.service.ts</code> file.</p>
<p>When you open the <code>recipe.service.ts</code> file you will see something like this :</p>
<pre><code class="lang-ts">
<span class="hljs-comment">// Other code...</span>
<span class="hljs-comment">// src/recipes/recipes.service.ts</span>
 findAll() {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`This action returns all recipe`</span>;
  }
<span class="hljs-comment">// Other code...</span>
</code></pre>
<p>NOW we will replace the <code>findAll</code> method with the following code:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.service.ts</span>
<span class="hljs-comment">// Other code...</span>

<span class="hljs-keyword">async</span> findAll() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.prisma.recipe.findMany();
}
<span class="hljs-comment">// Other code...</span>
</code></pre>
<p>In the above snippet:</p>
<ul>
<li>The <code>findAll</code> method utilizes Prisma's <code>findMany</code> function to retrieve all recipes from the database.</li>
<li>The <code>await</code> keyword is not necessary here because the <code>async</code> function implicitly wraps the returned value in a Promise.</li>
</ul>
<p>We've now successfully implemented the service method that our <code>findAll</code> controller will use to fetch all recipes.</p>
<p>Given that we already have seed data in our database, opening Swagger should allow us to retrieve all the recipes. Here's what you can expect to see:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/get-all-recipe-swagger.png" alt="Fetch All Recipes" width="600" height="400" loading="lazy">
<em>The Swagger UI displaying the result of the 'Fetch All Recipes' operation.</em></p>
<p>As depicted in the image above, our <code>GET /recipes</code> endpoint is functioning as expected, successfully fetching all recipes from our database. </p>
<p>This marks a significant milestone in our journey of building a robust recipe management system. Let's continue on and add some more features.</p>
<h3 id="heading-how-to-define-the-get-recipesid-endpoint">How to Define the <code>GET /recipes/{id}</code> Endpoint</h3>
<p>Let's now focus on the <code>GET /recipes/{id}</code> endpoint, which retrieves a specific recipe based on its ID. To implement this, we'll need to modify both the <code>controller</code> and the <code>service</code>.</p>
<p>First, navigate to the <code>recipes.controller.ts</code> file. Here, you'll find the <code>findOne</code> method, which is defined as follows:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.controller.ts</span>

<span class="hljs-comment">// other code ...</span>
<span class="hljs-meta">@Get</span>(<span class="hljs-string">':id'</span>)
<span class="hljs-keyword">async</span> findOne(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>) id: <span class="hljs-built_in">string</span>) {
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.recipeService.findOne(+id);
}
<span class="hljs-comment">// other code ...</span>
</code></pre>
<p>In this code:</p>
<ul>
<li>The <code>@Get(':id')</code> decorator maps to the <code>GET /recipes/{id}</code> endpoint.</li>
<li>The <code>findOne</code> method accepts an <code>id</code> parameter, which is extracted from the route parameters.</li>
</ul>
<p>Next, let's turn our attention to the <code>recipes.service.ts</code> file. Here, you'll find a placeholder <code>findOne</code> method:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.service.ts</span>
<span class="hljs-comment">// other code ...</span>
  findOne(id: <span class="hljs-built_in">number</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`This action returns a #<span class="hljs-subst">${id}</span> recipe`</span>;
  }

<span class="hljs-comment">// other code ...</span>
</code></pre>
<p>We'll replace this placeholder with a method that fetches a recipe based on its <code>id</code>:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.service.ts</span>

findOne(id: <span class="hljs-built_in">number</span>) {
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.prisma.recipe.findUnique({
    where: { id },
  });
}
</code></pre>
<p>In this code:</p>
<ul>
<li>The <code>findOne</code> method takes an <code>id</code> as an argument and uses Prisma's <code>findUnique</code> function to retrieve the recipe with the corresponding <code>id</code>.</li>
</ul>
<p>With the recent modifications, you've unlocked the ability to fetch individual recipes by their ID.</p>
<p>To see this feature in action, navigate to your Swagger page. Here's a snapshot of what you can expect:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/Get-by-id.png" alt="GET BY ID" width="600" height="400" loading="lazy">
<em>The Swagger UI displaying the result of the 'GET BY ID' operation.</em></p>
<p>Having achieved this milestone, we're ready to venture into creating our own recipes, adding to the existing ones in our database.</p>
<h3 id="heading-how-to-define-the-post-recipes-endpoint">How to Define the <code>POST /recipes</code> Endpoint</h3>
<p>The NestJS CLI has conveniently generated a <code>create</code> method for us when we created the resource for the <code>Recipe</code> model. Now, we need to implement the logic for this method in the <code>recipe.service.ts</code> file.</p>
<p>First, let's look at the <code>create</code> method in the <code>recipe.controller.ts</code> file:<br>We will see something like this:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.controller.ts</span>

<span class="hljs-comment">// other code ...</span>
<span class="hljs-meta">@Post</span>()
create(<span class="hljs-meta">@Body</span>() createRecipeDto: CreateRecipeDto) {
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.recipesService.create(createRecipeDto);
}
<span class="hljs-comment">// other code ...</span>
</code></pre>
<p>In this code:</p>
<ul>
<li>The <code>@Post()</code> decorator maps the method to the <code>POST /recipes</code> endpoint.</li>
<li>The <code>create</code> method accepts a <code>createRecipeDto</code> parameter, which is extracted from the request body.</li>
</ul>
<p>The NestJS CLI has thoughtfully provided us with DTO (Data Transfer Object) files within the <code>recipe</code> folder. One of these, <code>CreateRecipeDto</code>, will be our tool of choice for validating incoming client data.</p>
<p><strong>A Quick DTO Primer</strong>: If you're new to the concept of DTOs, they're essentially objects that carry data between processes. In the context of our application, we'll use DTOs to ensure the data we receive aligns with our expectations. If you're keen to delve deeper into DTOs, check out this comprehensive <a target="_blank" href="https://docs.nestjs.com/controllers#request-payloads">guide</a>.</p>
<p>Now, let's implement the <code>create</code> method in the <code>recipe.service.ts</code> file to interact with our database.</p>
<p>But before we proceed, let's harness the power of the DTO (Data Transfer Object) folder, generated by the Nest CLI, to model our data.</p>
<p>The <code>CreateRecipeDto</code> class, as shown below, is a prime example of a DTO. It's designed to validate incoming client data, ensuring it aligns with our expectations.</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/dto/create-recipe.dto.ts</span>
<span class="hljs-keyword">import</span> { IsString, IsOptional } <span class="hljs-keyword">from</span> <span class="hljs-string">'class-validator'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CreateRecipeDto {
  <span class="hljs-meta">@IsString</span>()
  title: <span class="hljs-built_in">string</span>;

  <span class="hljs-meta">@IsOptional</span>()
  <span class="hljs-meta">@IsString</span>()
  description?: <span class="hljs-built_in">string</span>;

  <span class="hljs-meta">@IsString</span>()
  ingredients: <span class="hljs-built_in">string</span>;

  <span class="hljs-meta">@IsString</span>()
  instructions: <span class="hljs-built_in">string</span>;
}
</code></pre>
<p>In this class, we're using the <code>class-validator</code> package to enforce data validation. This package offers a suite of decorators, such as <code>IsString</code> and <code>IsOptional</code>, which we've employed to validate the <code>title</code>, <code>description</code>, <code>ingredients</code>, and <code>instructions</code> fields. </p>
<p>With this setup, we can confidently ensure that these fields will always be strings, with <code>description</code> being optional.</p>
<p>Now, let's implement the <code>create</code> method in the <code>recipe.service.ts</code> file to interact with our database. When you open the <code>recipe.service.ts</code> file you will see something like this:</p>
<pre><code class="lang-ts">
<span class="hljs-comment">// src/recipes/recipes.service.ts</span>

<span class="hljs-comment">// other code ...</span>
  create(createRecipeDto: CreateRecipeDto) {
    <span class="hljs-keyword">return</span> <span class="hljs-string">'This action adds a new recipe'</span>;
  }

<span class="hljs-comment">// other code ...</span>
</code></pre>
<p>Replace the <code>create</code> method with the following code:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.service.ts</span>

<span class="hljs-comment">// other code ...</span>
create(createRecipeDto: CreateRecipeDto) {
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.prisma.recipe.create({
    data: createRecipeDto,
  });
}
<span class="hljs-comment">// other code ...</span>
</code></pre>
<p>In this code:</p>
<ul>
<li>The <code>create</code> method uses Prisma's <code>create</code> function to add a new recipe to the database. The data for the new recipe is provided by the <code>createRecipeDto</code>.</li>
</ul>
<p>With these changes, you can now create new recipes in your swagger page. Here's what you can expect to see:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/Creating-POST.png" alt="Creating a Recipe" width="600" height="400" loading="lazy">
<em>The Swagger UI displaying the process of creating a new recipe.</em></p>
<p>As depicted in the image above, we've successfully added a third recipe to our collection. This demonstrates the effectiveness of our POST method in creating new recipes.</p>
<h3 id="heading-how-to-define-the-patch-recipesid-endpoint">How to Define the <code>PATCH /recipes/{id}</code> Endpoint</h3>
<p>Having implemented the endpoints to create and retrieve recipes, let's now focus on updating a recipe. We'll implement the <code>PATCH /recipes/{id}</code> endpoint, which updates a specific recipe based on its ID. This requires modifications in both the <code>controller</code> and the <code>service</code>.</p>
<p>In the <code>recipes.controller.ts</code> file, locate the <code>update</code> method. This method is mapped to the <code>PATCH /recipes/{id}</code> endpoint:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.controller.ts</span>

<span class="hljs-comment">// other code ...</span>
<span class="hljs-meta">@Patch</span>(<span class="hljs-string">':id'</span>)
update(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>) id: <span class="hljs-built_in">string</span>, <span class="hljs-meta">@Body</span>() updateRecipeDto: UpdateRecipeDto) {
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.recipesService.update(+id, updateRecipeDto);
}
<span class="hljs-comment">// other code ...</span>
</code></pre>
<p>In this code:</p>
<ul>
<li>The <code>@Patch(':id')</code> decorator maps the method to the <code>PATCH /recipes/{id}</code> endpoint.</li>
<li>The <code>update</code> method accepts two parameters: <code>id</code> (extracted from the route parameters) and <code>updateRecipeDto</code> (extracted from the request body).</li>
</ul>
<p>Next, let's implement the <code>update</code> method in the <code>recipe.service.ts</code> file. When you open the <code>recipe.service.ts</code> file, you will see something like this:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.service.ts</span>

<span class="hljs-comment">// other code ...</span>
  update(id: <span class="hljs-built_in">number</span>, updateRecipeDto: UpdateRecipeDto) {
    <span class="hljs-keyword">return</span> <span class="hljs-string">`This action updates a #<span class="hljs-subst">${id}</span> recipe`</span>;
  }

<span class="hljs-comment">// other code ...</span>
</code></pre>
<p>Replace the <code>update</code> method with the following code:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.service.ts</span>

update(id: <span class="hljs-built_in">number</span>, updateRecipeDto: UpdateRecipeDto) {
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.prisma.recipe.update({
    where: { id },
    data: updateRecipeDto,
  });
}
</code></pre>
<p>In this code:</p>
<ul>
<li>The <code>update</code> method uses Prisma's <code>update</code> function to update the recipe in the database. The <code>where</code> clause specifies the recipe to update (based on <code>id</code>), and the <code>data</code> clause specifies the new data for the recipe (provided by <code>updateRecipeDto</code>).</li>
</ul>
<p>With the recent modifications, we've unlocked the ability to update individual recipes by their ID.</p>
<p>Let's put this new feature to the test by updating the recipe with an ID of 3.</p>
<p>Here's a snapshot of the current state of the recipe:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/by-id3.png" alt="Current Recipe Data" width="600" height="400" loading="lazy">
<em>Displaying the current data of a specific recipe.</em></p>
<p>As depicted above, this is the existing data for the recipe we're about to update.</p>
<p>After executing the update operation, here's how our recipe transforms:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/after-updating-id-3-response.png" alt="Updated Recipe Data" width="600" height="400" loading="lazy">
<em>Displaying the updated data of a specific recipe after modification.</em></p>
<p>As you can see, our update operation has successfully modified the recipe, demonstrating the effectiveness of our newly implemented feature.</p>
<p>Let's now turn our attention to deleting recipes.</p>
<h3 id="heading-how-to-define-the-delete-recipesid-endpoint">How to Define the <code>DELETE /recipes/{id}</code> Endpoint</h3>
<p>Having successfully defined the <code>GET</code>, <code>POST</code>, and <code>PATCH</code> endpoints, our next task is to implement the <code>DELETE /recipes/{id}</code> endpoint. This endpoint will let us remove a specific recipe using its ID. As with the previous endpoints, we'll need to make modifications in both the <code>controller</code> and the <code>service</code>.</p>
<p>In the <code>recipes.controller.ts</code> file, we have a <code>remove</code> method. This method is mapped to the <code>DELETE /recipes/{id}</code> endpoint:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.controller.ts</span>

<span class="hljs-meta">@Delete</span>(<span class="hljs-string">':id'</span>)
<span class="hljs-keyword">async</span> remove(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>, ParseIntPipe) id: <span class="hljs-built_in">number</span>) {
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.recipesService.remove(id);
}
</code></pre>
<p>In this updated code:</p>
<ul>
<li>The <code>@Delete(':id')</code> decorator maps the method to the <code>DELETE /recipes/{id}</code> endpoint.</li>
<li>The <code>remove</code> method accepts an <code>id</code> parameter, which is extracted from the route parameters and parsed to a number using <code>ParseIntPipe</code>.</li>
</ul>
<p>Next, let's implement the <code>remove</code> method in the <code>recipe.service.ts</code> file. Now with the <code>remove</code> method you see this:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.service.ts</span>
<span class="hljs-comment">// other code ...</span>
 <span class="hljs-meta">@Delete</span>(<span class="hljs-string">':id'</span>)
  remove(<span class="hljs-meta">@Param</span>(<span class="hljs-string">'id'</span>) id: <span class="hljs-built_in">string</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.recipeService.remove(+id);
  }

  <span class="hljs-comment">// other code ...</span>
</code></pre>
<p>Replace the <code>remove</code> method with this code:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// src/recipes/recipes.service.ts</span>


<span class="hljs-comment">// other code </span>
<span class="hljs-keyword">async</span> remove(id: <span class="hljs-built_in">number</span>) {
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.prisma.recipe.delete({
    where: { id },
  });
}

<span class="hljs-comment">// other code ..</span>
</code></pre>
<p>In this code, the <code>remove</code> method uses Prisma's <code>delete</code> function to remove the recipe with the specified <code>id</code> from the database.</p>
<p>In this code:</p>
<ul>
<li>The <code>remove</code> method uses Prisma's <code>delete</code> function to remove the recipe with the corresponding <code>id</code> from the database.</li>
</ul>
<p>With these changes, you can now delete individual recipes by their ID. Check the Swagger page to see the updated API documentation.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/delet-by-id.png" alt="Delete Recipe Data" width="600" height="400" loading="lazy">
<em>Displaying the process of deleting a specific recipe.</em></p>
<h2 id="heading-summary-and-final-remarks">Summary and Final Remarks</h2>
<p>In this handbook, we've journeyed through the process of building a REST API using NestJS and Prisma. </p>
<p>We started by setting up a NestJS project, configuring a PostgreSQL database using Docker, and integrating Prisma.</p>
<p>We then dove into the heart of our application, creating a <code>Recipe</code> model and implementing CRUD operations for it. This involved generating RESTful routes, integrating the Prisma Client into our <code>Recipe</code> service, and crafting the logic for each operation.</p>
<p>This guide serves as a solid foundation for your future projects. Feel free to expand upon it, adding more features and functionalities to suit your needs. Thank you for following along, and happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Set Up Message Queues for Async Tasks with RabbitMQ in Nest.js Apps ]]>
                </title>
                <description>
                    <![CDATA[ When you're developing programs, certain services can block or slow down the speed of your application. For example, CPU-intensive tasks like audio transcribing or file processing. So you might wonder – how do you make sure your application runs with... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/message-queues-with-rabbitmq-in-nest-js/</link>
                <guid isPermaLink="false">66bb51f80fc4910f8f7dfba8</guid>
                
                    <category>
                        <![CDATA[ nestjs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ performance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ queue ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Okoye Chukwuebuka Victor ]]>
                </dc:creator>
                <pubDate>Thu, 14 Dec 2023 01:20:25 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/12/articlePhoto.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When you're developing programs, certain services can block or slow down the speed of your application. For example, CPU-intensive tasks like audio transcribing or file processing.</p>
<p>So you might wonder – how do you make sure your application runs without breaking? To handle this, you can send tasks to a queue outside your application's flow.</p>
<h2 id="heading-what-is-a-message-queue">What is a Message Queue?</h2>
<p>A message queue is a tool that facilitates the communication and transfer of data between services within a single application (or externally). It stores these data or messages using the First-In-First-Out (FIFO) principle. This means that older data that's passed into these queues gets processed before newer data.</p>
<p>Different components make up a message queue, such as:</p>
<ul>
<li><strong>Messages</strong>: These are the data that are sent to the queue. They are often referred to as jobs.</li>
<li><strong>Queues</strong>: These are the data structures used for storing messages.</li>
<li><strong>Producers</strong>: These are a service that sends messages or data into the queue system.</li>
<li><strong>Consumers</strong>: These are a service that listens to the queue and executes messages passed in it.</li>
</ul>
<h3 id="heading-message-queuing-tools">Message Queuing Tools</h3>
<p>Now, there are various message queuing tools you can use in asynchronous systems, like the following:</p>
<ul>
<li><strong>RabbitMQ</strong>: a reliable and flexible option for implementing message queues in applications.</li>
<li><strong>Apache</strong> <strong>Kafka</strong>: an efficient message queuing tool, also very good at event stream processing.</li>
<li><strong>Redis</strong>: an in-memory store used for message queuing, caching, and data processing.</li>
</ul>
<p>Note that some of these tools are not limited to message queuing but can be used for other purposes as well, like stream processing.</p>
<p>In this article, you will create a simple Nest.js project which will use RabbitMQ as the Message Queue Service Provider.</p>
<p>The tutorial will be divided into 3 parts:</p>
<ul>
<li><a class="post-section-overview" href="#heading-how-to-set-up-a-nestjs-project">How to Set Up a Nest.js Project for Basic User Registration Flow</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-an-email-service-for-user-registration">How to Set Up an Email Service for User Registration</a></li>
<li><a class="post-section-overview" href="#heading-how-to-integrate-a-queue-service-using-rabbitmq">How to Integrate a Queue Service using RabbitMQ</a></li>
</ul>
<h3 id="heading-prerequisites">Prerequisites</h3>
<ul>
<li>You'll need to have Node installed on your system. If you don't have it, here is its official site: <a target="_blank" href="https://nodejs.org/en">https://nodejs.org/en</a>.</li>
<li>You'll need to have Node Package Manager (NPM) installed, which you can download here if you don't have it: <a target="_blank" href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm">https://docs.npmjs.com/downloading-and-installing-node-js-and-npm</a>.</li>
<li>You'll need to have installed RabbitMQ. Here is where you can get it in case you haven't yet: <a target="_blank" href="https://www.rabbitmq.com/download.html">https://www.rabbitmq.com/download.html</a></li>
<li>You'll need to have a text editor. For this article, I'll use VSCode. You can download it here: <a target="_blank" href="https://code.visualstudio.com/download">https://code.visualstudio.com/download</a> or use the code editor of your choice.</li>
</ul>
<h2 id="heading-how-to-set-up-a-nestjs-project">How to Set Up a Nest.js Project</h2>
<p>Spinning up a Nest.js application is fast and simple if you use the Nest CLI. Open up your terminal and enter this command below to install the CLI:</p>
<pre><code class="lang-bash"> $ npm install -g @nestjs/cli
</code></pre>
<p>This installs the Nest.js CLI globally on your system, meaning you can call the CLI commands regardless of the directory you are currently in.</p>
<p>Moving forward, to create a simple REST API project, you will enter the command below:</p>
<pre><code class="lang-bash">nest new simple-queue
</code></pre>
<p>Simple-queue here is the directory name that will be created. Inputting this command gives you a prompt to select a package manager.</p>
<p>When that's done, navigate to the created directory and open it in your text editor by entering this command:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> simple-queue &amp;&amp; code .
</code></pre>
<p>This opens up your text editor. We want to work on a project that will best show how a message queue can be used in a real-world scenario – so let's set up a basic user registration form. On successful data entry it sends an email to the user, but you'll handle the email service separately by passing it into a queue to improve performance.</p>
<p>For this, we'll be using an SQLite database, TypeOrm, class-validators, and the dotenv package so you can secure your config variables. Go ahead to install them by typing this command in your terminal:</p>
<pre><code class="lang-bash">npm install --save @nestjs/typeorm typeorm sqlite3 class-validator dotenv
</code></pre>
<p>When the installation is complete, go to your root app module, and then include the TypeOrm configuration for your database. </p>
<p>SQLite is a lightweight SQL database which allows us to quickly spin up and test data. It's optimal for this use case – and now we'll configure it.</p>
<h3 id="heading-configuring-the-sqlite-database">Configuring the SQLite Database</h3>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">"@nestjs/common"</span>;
<span class="hljs-keyword">import</span> { TypeOrmModule } <span class="hljs-keyword">from</span> <span class="hljs-string">"@nestjs/typeorm"</span>;
<span class="hljs-keyword">import</span> { AppController } <span class="hljs-keyword">from</span> <span class="hljs-string">"./app.controller"</span>;
<span class="hljs-keyword">import</span> { AppService } <span class="hljs-keyword">from</span> <span class="hljs-string">"./app.service"</span>;

<span class="hljs-meta">@Module</span>({
  imports: [
    TypeOrmModule.forRoot({
      <span class="hljs-keyword">type</span>:<span class="hljs-string">'sqlite'</span>,
      database: <span class="hljs-string">'mini-db.sqlite'</span>,
      entities: [__dirname + <span class="hljs-string">'/**/*.entity{.ts,.js}'</span>],
      synchronize: <span class="hljs-literal">true</span>,  
  })],
  controllers: [AppController],
  providers: [AppService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule {}
</code></pre>
<p>Congrats! You have successfully connected a DB to your project. Now it's time to create the services that will handle the user registration. </p>
<p>In order to do this, you will have to go back to your dear friend the Nest CLI. There, you'll be inputting a different command to help generate a resource folder for the User, which will contain the entity, service, dto, and the controller.</p>
<p>To do this, open your terminal and enter in this command:</p>
<pre><code class="lang-bash">nest generate resource users
</code></pre>
<p>A prompt to select your transport layer will be shown. Select the first one which is the <code>REST API</code>. Then, another prompt will ask if you would like to generate CRUD endpoints – you can type Yes. Then you can make modifications according to your requirements.</p>
<p>To proceed, you first have to define what information each user should have. First, create a User entity. You can do this by navigating to the user entity file in the created entity subfolder in the user folder. Then define the user data like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Entity, PrimaryGeneratedColumn, Column } <span class="hljs-keyword">from</span> <span class="hljs-string">"typeorm"</span>;

<span class="hljs-meta">@Entity</span>(<span class="hljs-string">'users'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> User {
  <span class="hljs-meta">@PrimaryGeneratedColumn</span>(<span class="hljs-string">'uuid'</span>)
  id: <span class="hljs-built_in">string</span>;

  <span class="hljs-meta">@Column</span>({ length: <span class="hljs-number">100</span>, unique: <span class="hljs-literal">true</span> })
  username: <span class="hljs-built_in">string</span>;

  <span class="hljs-meta">@Column</span>({ length: <span class="hljs-number">100</span>, unique: <span class="hljs-literal">true</span> })
  email: <span class="hljs-built_in">string</span>;
}
</code></pre>
<p>For this mini-project, you'll use basic user data to make the process faster. The username and email field have been set to be unique, meaning that there won't be a duplicate of the data instance passed in for this user table.</p>
<p>Now having done this, modify the create user dto file that was generated like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { IsNotEmpty, IsString, IsEmail } <span class="hljs-keyword">from</span> <span class="hljs-string">"class-validator"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CreateUserDto {
    <span class="hljs-meta">@IsNotEmpty</span>()
    <span class="hljs-meta">@IsString</span>()
    username: <span class="hljs-built_in">string</span>;

    <span class="hljs-meta">@IsNotEmpty</span>()
    <span class="hljs-meta">@IsString</span>()
    <span class="hljs-meta">@IsEmail</span>()
    email: <span class="hljs-built_in">string</span>;
  }
</code></pre>
<p>This was created to validate the payload that will be sent in your request by using the class-validator package.</p>
<p>Now, modify the <code>create</code> method in the user service file.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">"@nestjs/common"</span>;
<span class="hljs-keyword">import</span> { InjectRepository } <span class="hljs-keyword">from</span> <span class="hljs-string">"@nestjs/typeorm"</span>;
<span class="hljs-keyword">import</span> { Repository } <span class="hljs-keyword">from</span> <span class="hljs-string">"typeorm"</span>;
<span class="hljs-keyword">import</span> { CreateUserDto } <span class="hljs-keyword">from</span> <span class="hljs-string">"./dto/create-user.dto"</span>;
<span class="hljs-keyword">import</span> { User } <span class="hljs-keyword">from</span> <span class="hljs-string">"./entities/user.entity"</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
    <span class="hljs-meta">@InjectRepository</span>(User)
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> userRepository: Repository&lt;User&gt;
  </span>) {}
  <span class="hljs-keyword">async</span> create(createUserDto: CreateUserDto): <span class="hljs-built_in">Promise</span>&lt;User&gt; {
    <span class="hljs-keyword">const</span> newUser = <span class="hljs-built_in">this</span>.userRepository.create(createUserDto);
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userRepository.save(newUser);
  }
}
</code></pre>
<p>Next you'll modify the controller file. You've already defined the <code>create</code> endpoint, so you'll just have to clean up the other endpoints that are not needed.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Controller, Post, Body } <span class="hljs-keyword">from</span> <span class="hljs-string">"@nestjs/common"</span>;
<span class="hljs-keyword">import</span> { CreateUserDto } <span class="hljs-keyword">from</span> <span class="hljs-string">"./dto/create-user.dto"</span>;
<span class="hljs-keyword">import</span> { UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">"./users.service"</span>;

<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'users'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersController {
 <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> usersService: UsersService</span>) {}
  <span class="hljs-meta">@Post</span>()
  create(<span class="hljs-meta">@Body</span>() createUserDto: CreateUserDto) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.usersService.create(createUserDto);
  }
}
</code></pre>
<p>Open up the user module file and make some adjustments by adding the import field to the Module decorator and using the TypeOrmModule property.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.service'</span>;
<span class="hljs-keyword">import</span> { UsersController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.controller'</span>;
<span class="hljs-keyword">import</span> { TypeOrmModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/typeorm'</span>;
<span class="hljs-keyword">import</span> { User } <span class="hljs-keyword">from</span> <span class="hljs-string">'./entities/user.entity'</span>;

<span class="hljs-meta">@Module</span>({
  imports: [TypeOrmModule.forFeature([User])],
  controllers: [UsersController],
  providers: [UsersService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersModule {}
</code></pre>
<p>Next, start up your server by entering this command on your terminal: <code>npm run start:dev</code>. Once the server is up and running, open up your API client of choice. For this article, we'll use Postman. Then make a POST request to the endpoint, which will be <code>localhost:3000/users</code>, providing the payload data required.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696695190655/b8b3b246-0961-4655-aaee-081b9ecff35e.png" alt="Image" width="898" height="409" loading="lazy">
<em>A request was made and a user instance was created.</em></p>
<p>Next up is adding an email service to your project which will help notify new users who are registering.</p>
<h2 id="heading-how-to-set-up-an-email-service-for-user-registration">How to Set Up an Email Service for User Registration</h2>
<p>For this, you'll use some packages which are required to create an email service. Open up your terminal and input the command below to install these packages:</p>
<pre><code class="lang-bash">npm install --save @nestjs-modules/mailer nodemailer
</code></pre>
<p>When these packages are installed, you can now implement the mail service. Using the Nest CLI, create a mailer module and service by entering this command in your terminal:</p>
<pre><code class="lang-bash">nest generate module email &amp;&amp; nest generate service email
</code></pre>
<p>When it's done, open up the newly created module file in the mail folder. You'll use the MailerModule property of the <code>@nestjs-modules/mailer</code> package to configure your mail service here. It requires an SMTP client whose keys you'll need to configure this MailerModule. </p>
<p>For that you can use <a target="_blank" href="https://app.elasticemail.com/api/">https://app.elasticemail.com</a> to get these SMTP keys. Sign up and connect to the SMTP API. You'll then be given keys for your private use.</p>
<p>Note that this free mode of the SMTP client has limitations and it cannot send to all emails – so you should use a test email service.</p>
<h3 id="heading-how-to-configure-the-mailer-module">How to Configure the Mailer Module</h3>
<p>Once you have gotten that set up, go back to your application and create a <strong>.env</strong> file. Set your secrets for the SMTP keys. Then configure your MailerModule like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Global, Module } <span class="hljs-keyword">from</span> <span class="hljs-string">"@nestjs/common"</span>;
<span class="hljs-keyword">import</span> { EmailService } <span class="hljs-keyword">from</span> <span class="hljs-string">"./email.service"</span>;
<span class="hljs-keyword">import</span> { MailerModule } <span class="hljs-keyword">from</span> <span class="hljs-string">"@nestjs-modules/mailer"</span>;

<span class="hljs-built_in">require</span>(<span class="hljs-string">'dotenv'</span>).config();
<span class="hljs-meta">@Global</span>()
<span class="hljs-meta">@Module</span>({
  imports: [
    MailerModule.forRoot({
      transport: {
        service: <span class="hljs-string">'QueueTest'</span>,
        host: process.env.SMTP_HOST,
        port: process.env.SMTP_PORT,
        auth: {
          user: process.env.SMTP_USER,
          pass: process.env.SMTP_PASSWORD,
        },
      },
      defaults: {
        <span class="hljs-keyword">from</span>: process.env.FROM_EMAIL,
      },
    }),
  ],
  providers: [EmailService]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> EmailModule {}
</code></pre>
<p>The global decorator was set in order to make sure the MailModule can be called anywhere in your application. Make sure your secrets are properly loaded and thaqt you have a valid Email set in the <strong>from: process.env.FROM_EMAIL.</strong></p>
<p>Check to make sure that the EmailModule is also imported in the root App Module the same way your UsersModule was imported in the Imports Array of the App Module.</p>
<p>Next, open your email service file – you'll need to make some modifications to the EmailService class. Add a constructor and call the MailService property from the <code>@nestjs-modules/mailer</code> package. Then go ahead and create a function that will handle sending the emails.</p>
<p>Below is a class and method that does this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { MailerService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs-modules/mailer'</span>;
<span class="hljs-keyword">import</span> { HttpException, HttpStatus, Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> EmailService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> mailerService: MailerService</span>) {}
  <span class="hljs-keyword">async</span> sendEmail(options: { email: <span class="hljs-built_in">string</span>; subject: <span class="hljs-built_in">string</span>; html: <span class="hljs-built_in">string</span>;
  }) {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> message = {
        to: options.email,
        subject: options.subject,
        html: options.html
      };
      <span class="hljs-keyword">const</span> emailSend = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.mailerService.sendMail({
        ...message,
      });
      <span class="hljs-keyword">return</span> emailSend;
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> HttpException(<span class="hljs-string">'Error'</span>, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }
}
</code></pre>
<p>Now you've defined the method to send an email. You've also put an exception handler in place for better error handling.</p>
<p>Now it's time to add this newly created service to your user registration flow.</p>
<p>Navigate to your user service file, and add the mail service to your constructor as a provider. Then call the service in your <code>create user</code> method like this:</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
    <span class="hljs-meta">@InjectRepository</span>(User)
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> userRepository: Repository&lt;User&gt;,
    <span class="hljs-keyword">private</span> emailService: EmailService
  </span>) {}
  <span class="hljs-keyword">async</span> create(createUserDto: CreateUserDto): <span class="hljs-built_in">Promise</span>&lt;User&gt; {
    <span class="hljs-keyword">const</span> newUser = <span class="hljs-built_in">this</span>.userRepository.create(createUserDto);
    <span class="hljs-keyword">const</span> user =  <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userRepository.save(newUser);
      <span class="hljs-keyword">const</span> emailData = {
        email: user.email,
        subject: <span class="hljs-string">'Welcome to Our Community'</span>,
        html: <span class="hljs-string">`&lt;p&gt;Hello <span class="hljs-subst">${user.username}</span>,&lt;/p&gt;
        &lt;p&gt;Welcome to our community! Your account is now active.&lt;/p&gt;
        &lt;p&gt;Enjoy your time with us!&lt;/p&gt;`</span>,
      };
      <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.emailService.sendEmail(emailData)
    <span class="hljs-keyword">return</span> user
  }
}
</code></pre>
<p>Make sure to modify your modules in order to correct any dependency injection errors. In your email module file, add the EmailService to the exports array:</p>
<pre><code class="lang-typescript"> providers: [EmailService],
 <span class="hljs-built_in">exports</span>: [EmailService]
</code></pre>
<p>Add it below your providers to export the Email Service so it can be accessed in other modules. Then import the EmailModule to your User module file and add it to your import array like this:</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@Module</span>({
  imports: [TypeOrmModule.forFeature([User]), EmailModule],
  controllers: [UsersController],
  providers: [UsersService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersModule {}
</code></pre>
<p>Now it's time to test it. Get a free account from any online email testing platform and open Postman. Make a request to the <code>create user</code> endpoint with your valid email. You should get an email response like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696695108644/25aa9e76-da00-436b-9e43-f0c978f87c6f.png" alt="Image" width="712" height="272" loading="lazy">
<em>Email response you should get</em></p>
<h2 id="heading-how-to-integrate-a-queue-service-using-rabbitmq">How to Integrate a Queue Service using RabbitMQ</h2>
<p>To get started with this, you'll have to install some packages that let you implement queues using RabbitMQ. Enter the command below to install these packages:</p>
<pre><code class="lang-bash">npm install --save amqplib @types/amqplib amqp-connection-manager
</code></pre>
<h3 id="heading-configure-the-producer-service">Configure the Producer Service</h3>
<p>Once installation is complete, it's time to configure RabbitMQ. You'll create a new folder in your src directory and name it queues. Then create the queue producer file. Import these packages and set them up like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { HttpException, HttpStatus, Injectable, Logger } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> amqp, { ChannelWrapper } <span class="hljs-keyword">from</span> <span class="hljs-string">'amqp-connection-manager'</span>;
<span class="hljs-keyword">import</span> { Channel } <span class="hljs-keyword">from</span> <span class="hljs-string">'amqplib'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ProducerService {
  <span class="hljs-keyword">private</span> channelWrapper: ChannelWrapper;
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) {
    <span class="hljs-keyword">const</span> connection = amqp.connect([<span class="hljs-string">'amqp://localhost'</span>]);
    <span class="hljs-built_in">this</span>.channelWrapper = connection.createChannel({
      setup: <span class="hljs-function">(<span class="hljs-params">channel: Channel</span>) =&gt;</span> {
        <span class="hljs-keyword">return</span> channel.assertQueue(<span class="hljs-string">'emailQueue'</span>, { durable: <span class="hljs-literal">true</span> });
      },
    });
  }

  <span class="hljs-keyword">async</span> addToEmailQueue(mail: <span class="hljs-built_in">any</span>) {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.channelWrapper.sendToQueue(
        <span class="hljs-string">'emailQueue'</span>,
        Buffer.from(<span class="hljs-built_in">JSON</span>.stringify(mail)),
        {
          persistent: <span class="hljs-literal">true</span>,
        },
      );
      Logger.log(<span class="hljs-string">'Sent To Queue'</span>);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> HttpException(
        <span class="hljs-string">'Error adding mail to queue'</span>,
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }
}
</code></pre>
<p>The AMQP connection was set and is running on localhost with the default RabittMQ port which is 5432. You also established a channel on that connection with an option input which is executed anytime a new channel is created. This helps if you have any configuration for that channel. </p>
<p>You also created an <code>emailQueue</code> with the assertQueue property which checks that a queue with that name does not already exist. If it does exist, it has no effect so it's idempotent. </p>
<p>Then you created an option <code>durable: true</code> to make sure that the queue will survive a server restart.</p>
<p>Next, you defined the method to add the email data to a queue. This calls the <code>sendToQueue</code> property of the channelWrapper, passing in the queue name you want to send the data to. Ideally, it should be the same name as the one you defined with the assertQueue property.</p>
<p>The second argument is the mail data, but firstly you converted it to a JSON string then to a Buffer. You do this because messages in RabbitMQ are mostly transmitted as binary data.</p>
<p>You can then set an option <code>persistent: true</code> to ensure that the data being sent to the queue won't be lost if the server crashes. Then with some error handling and the method to send messages to the queue, it's good to go.</p>
<h3 id="heading-set-up-the-consumer-service">Set Up the Consumer Service</h3>
<p>Now that you've configured the producer service, it's time to set up the consumer service. </p>
<p>Create another file in the queue sub-folder. It's quite similar, but in this case, you will be consuming the data from the queue. Below is the configuration for the consumer service:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Injectable, OnModuleInit, Logger } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> amqp, { ChannelWrapper } <span class="hljs-keyword">from</span> <span class="hljs-string">'amqp-connection-manager'</span>;
<span class="hljs-keyword">import</span> { ConfirmChannel } <span class="hljs-keyword">from</span> <span class="hljs-string">'amqplib'</span>;
<span class="hljs-keyword">import</span> { EmailService } <span class="hljs-keyword">from</span> <span class="hljs-string">'src/email/email.service'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ConsumerService <span class="hljs-keyword">implements</span> OnModuleInit {
  <span class="hljs-keyword">private</span> channelWrapper: ChannelWrapper;
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> logger = <span class="hljs-keyword">new</span> Logger(ConsumerService.name);
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> emailService: EmailService</span>) {
    <span class="hljs-keyword">const</span> connection = amqp.connect([<span class="hljs-string">'amqp://localhost'</span>]);
    <span class="hljs-built_in">this</span>.channelWrapper = connection.createChannel();
  }

  <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> onModuleInit() {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.channelWrapper.addSetup(<span class="hljs-keyword">async</span> (channel: ConfirmChannel) =&gt; {
        <span class="hljs-keyword">await</span> channel.assertQueue(<span class="hljs-string">'emailQueue'</span>, { durable: <span class="hljs-literal">true</span> });
        <span class="hljs-keyword">await</span> channel.consume(<span class="hljs-string">'emailQueue'</span>, <span class="hljs-keyword">async</span> (message) =&gt; {
          <span class="hljs-keyword">if</span> (message) {
            <span class="hljs-keyword">const</span> content = <span class="hljs-built_in">JSON</span>.parse(message.content.toString());
            <span class="hljs-built_in">this</span>.logger.log(<span class="hljs-string">'Received message:'</span>, content);
            <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.emailService.sendEmail(content);
            channel.ack(message);
          }
        });
      });
      <span class="hljs-built_in">this</span>.logger.log(<span class="hljs-string">'Consumer service started and listening for messages.'</span>);
    } <span class="hljs-keyword">catch</span> (err) {
      <span class="hljs-built_in">this</span>.logger.error(<span class="hljs-string">'Error starting the consumer:'</span>, err);
    }
  }
}
</code></pre>
<p>First, you defined your consumer class. For this, it implements the <code>onModuleInit</code> interface which is provided by <code>@nestJs/common</code>. This specifies that the defined class should have a method named <code>onModuleInit()</code>. </p>
<p>Like the name says, the method will be called automatically during the module initialization which is when the module containing this class is loaded. </p>
<p>In the class constructor, you added the <code>emailService</code> because you'll be using the <code>sendEmail</code> method of that class.</p>
<p>In the <code>onModuleInit()</code> method, you defined a channel. This is necessary because you need a channel to consume messages from a queue.</p>
<p>From this, the channel is then used to assert a queue which should be similar in name and options to what you have on your producer service. If it's not, you won't be able to listen to the queue created on the producer service. </p>
<p>Then you used the consume method of channel to listen and execute the message coming from the queue you have registered.</p>
<p>Recall that before, you had to convert the message to Buffer in order to send it into a queue. Now, you have to convert it to a JavaScript object. Then call the emailService method to send an email and pass in the converted JavaScript object as the argument of that method.</p>
<p>Finally, you called the <code>ack</code> method which is used to inform the queue that the message has been received and processed successfully in order for it to be removed from the queue.</p>
<p>Now that you've defined these services, create a module file and set them in the providers array. Then export the producer service because you will be calling it in another module.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { ConsumerService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./consumer.file'</span>;
<span class="hljs-keyword">import</span> { ProducerService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./producer.file'</span>;

<span class="hljs-meta">@Module</span>({
  providers: [ProducerService, ConsumerService],
  <span class="hljs-built_in">exports</span>: [ProducerService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> QueueModule {}
</code></pre>
<p>Next up is to add the emails being sent on user registration to the queue service that you just created. </p>
<p>Navigate back to your user service file and make some modifications: replace the email service with the producer service as a provider in the constructor, and then call the service and the method to add to the email queue as shown below:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">"@nestjs/common"</span>;
<span class="hljs-keyword">import</span> { InjectRepository } <span class="hljs-keyword">from</span> <span class="hljs-string">"@nestjs/typeorm"</span>;
<span class="hljs-keyword">import</span> { Repository } <span class="hljs-keyword">from</span> <span class="hljs-string">"typeorm"</span>;
<span class="hljs-keyword">import</span> { CreateUserDto } <span class="hljs-keyword">from</span> <span class="hljs-string">"./dto/create-user.dto"</span>;
<span class="hljs-keyword">import</span> { User } <span class="hljs-keyword">from</span> <span class="hljs-string">"./entities/user.entity"</span>;
<span class="hljs-keyword">import</span> { ProducerService } <span class="hljs-keyword">from</span> <span class="hljs-string">"src/queues/producer.file"</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
    <span class="hljs-meta">@InjectRepository</span>(User)
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> userRepository: Repository&lt;User&gt;,
    <span class="hljs-keyword">private</span> producerService: ProducerService,
  </span>) {}
  <span class="hljs-keyword">async</span> create(createUserDto: CreateUserDto): <span class="hljs-built_in">Promise</span>&lt;User&gt; {
    <span class="hljs-keyword">const</span> newUser = <span class="hljs-built_in">this</span>.userRepository.create(createUserDto);
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userRepository.save(newUser);
    <span class="hljs-keyword">const</span> emailData = {
      email: user.email,
      subject: <span class="hljs-string">'Welcome to Our Community'</span>,
      html: <span class="hljs-string">`&lt;p&gt;Hello <span class="hljs-subst">${user.username}</span>,&lt;/p&gt;
        &lt;p&gt;Welcome to our community! Your account is now active.&lt;/p&gt;
        &lt;p&gt;Enjoy your time with us!&lt;/p&gt;`</span>,
    };
    <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.producerService.addToEmailQueue(emailData);
    <span class="hljs-keyword">return</span> user;
  }
}
</code></pre>
<p>Also in the user module file, replace the EmailModule with that of the QueueModule to avoid dependency injection errors when you start up your server.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.service'</span>;
<span class="hljs-keyword">import</span> { UsersController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.controller'</span>;
<span class="hljs-keyword">import</span> { TypeOrmModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/typeorm'</span>;
<span class="hljs-keyword">import</span> { User } <span class="hljs-keyword">from</span> <span class="hljs-string">'./entities/user.entity'</span>;
<span class="hljs-keyword">import</span> { QueueModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'src/queues/queue.module'</span>;

<span class="hljs-meta">@Module</span>({
  imports: [TypeOrmModule.forFeature([User]), QueueModule],
  controllers: [UsersController],
  providers: [UsersService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersModule {}
</code></pre>
<p>Now finally, it's time to test the user registration flow again. So navigate back to Postman and then type in a valid email and username and hit enter. On the terminal of your server running, you will see logs that were set in order to track the way the message got sent and how it was received and executed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696982914939/7f28f0e3-22e3-462c-8956-0bd2156d4c10.png" alt="Image" width="800" height="153" loading="lazy">
<em>Logs that help you track the message</em></p>
<p>You can also open up the RabbitMQ dashboard to view queue activity on <a target="_blank" href="http://localhost:15672/">http://localhost:15672</a>, By default the user is "guest", so enter in <code>guest</code> for the username and password.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702377899227/4158d8b2-2b9b-424e-bd0b-a4203648eb50.png" alt="Image" width="906" height="523" loading="lazy">
<em>RabbitMQ Queues and Streams</em></p>
<p>Here's the link to the <a target="_blank" href="https://github.com/ChuloWay/article-nestjs-queue">GitHub repository</a>. Feel free to check it out whenever you're stuck.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article you learned what a message queue is along with some major components of how they work. You also built a mini Nest.js project and implemented an email service in it. Finally, you integrated the queue service into your project, showing how it works in a real-life scenario.</p>
<p>Understanding message queue behaviors and patterns is an essential skill when developing scalable applications. This helps reduce lag and improves the speed and efficiency of your applications. </p>
<p>I hope you enjoyed reading this article. You can follow me on <a target="_blank" href="https://twitter.com/OkoyeVictorr">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Exception Filters to Catch Bugs in Nest.js ]]>
                </title>
                <description>
                    <![CDATA[ It's common to find errors and bugs in your code if you're a software developer. They might occur because of incorrect input, from passing the wrong data types, or because of delays or response timeouts.  And even though errors and bugs are a part of... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/exception-filters-in-nestjs/</link>
                <guid isPermaLink="false">66bb51f1b0a396d22e4116f7</guid>
                
                    <category>
                        <![CDATA[ debugging ]]>
                    </category>
                
                    <category>
                        <![CDATA[ error handling ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ nestjs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Okoye Chukwuebuka Victor ]]>
                </dc:creator>
                <pubDate>Fri, 23 Jun 2023 21:38:23 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/06/brett-jordan-XWar9MbNGUY-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>It's common to find errors and bugs in your code if you're a software developer. They might occur because of incorrect input, from passing the wrong data types, or because of delays or response timeouts. </p>
<p>And even though errors and bugs are a part of life, they can stress you out and decrease your productivity. Fortunately, you can limit the number of pests in your code by taking proactive measures to prevent and fix them. </p>
<p>In this article, you will learn how best to utilize exception filters to limit disruptions in your code implementations.</p>
<h2 id="heading-what-are-exception-filters">What Are Exception Filters?</h2>
<p>Exception filters are constructs of a programming language that help you handle exceptions or errors found in services or controller classes. Using these filters improves the efficiency of your codebase and makes errors more traceable, which helps you resolve them.</p>
<h3 id="heading-what-are-exception-filters-in-nestjs">What are Exception Filters in Nest.js?</h3>
<p>Nest.js has an inbuilt exception filter interface that you import from the <code>@nestjs/common package</code>. This interface gives you precise information about exceptions you may encounter so that you can know how to fix them. </p>
<p>Some built-in exception filters include <code>NotFoundException</code>, <code>UnauthorizedException</code>, and <code>RequestTimeOutException</code>, among others.</p>
<h2 id="heading-how-to-create-a-custom-exception-filter">How to Create a Custom Exception Filter</h2>
<p>To create a custom exception filter class, you define it with a <code>@Catch</code> decorator that takes in the type of exception the filter should catch. This class then implements the <code>ExceptionFilter</code> interface. This way you will have access to the <code>catch</code> method that the interface provides. </p>
<p>NestJS allows you to create your own exception filters so you can define what sort of information it should return.</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@Catch</span>(HttpException)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> TestExceptionFilter <span class="hljs-keyword">implements</span> ExceptionFilter {
  <span class="hljs-keyword">catch</span>(exception: HttpException, host: ArgumentsHost) {
    <span class="hljs-keyword">const</span> ctx = host.switchToHttp();
    <span class="hljs-keyword">const</span> response = ctx.getResponse&lt;Response&gt;();
    <span class="hljs-keyword">const</span> request = ctx.getRequest&lt;Request&gt;();
    <span class="hljs-keyword">const</span> status = exception.getStatus();

    response
      .status(status)
      .json({
        statusCode: status,
        timestamp: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().toISOString(),
        path: request.url,
      });
  }
}
</code></pre>
<p>As you can see above, the catch method takes in two argument inputs: the <code>exception:HttpException</code> and the <code>host:argumentsHost</code>. </p>
<p><code>HttpException</code> is the exception thrown when an <code>HTTP</code> request fails and returns the appropriate Error Message with a status code as a response to the client. </p>
<p>The <code>argumentsHost</code> parameter provides information about the current request and response cycle. Here the code extracts the Response and Request objects from the <code>ArgumentsHost</code> object using the <code>switchToHttp</code> method. It then calls the <code>getStatus</code> method from the <code>HttpException</code> object in order to retrieve the <code>HTTP</code> status code of the error.</p>
<p> A <code>JSON</code> object gets returned. It contains the status code, the error timestamp, and the request URL, setting the <code>HTTP</code> response status code to be the error status code.</p>
<p>Another exciting thing to note is that you can modify the status code and error message of existing exception filters like <code>NotFoundException</code> so that they display your own custom error message and status code. Here is an illustration below:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> NotFoundException <span class="hljs-keyword">extends</span> HttpException {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">message: <span class="hljs-built_in">string</span></span>) {
    <span class="hljs-built_in">super</span>(message || <span class="hljs-string">'Not Found'</span>, HttpStatus.NOT_FOUND);
  }
}
</code></pre>
<p>The example above shows that the <code>NotFoundException</code> class was modified to accept a <code>message</code> parameter in the constructor method or give a default value of 'Not Found'. </p>
<p>By doing this you are now able to customize an error message for your <code>NotFoundException</code> class and return a <code>404</code> status code.</p>
<h2 id="heading-how-to-bind-exception-filters-in-nestjs">How to Bind Exception Filters in Nest.js</h2>
<p>You might be wondering how you can implement the custom or modified exception you've created for your application. Well, you use something called <strong>binding</strong>. </p>
<p>There are several ways in which you can bind exception filters to your application. Here are three major ways you can do it:</p>
<ol>
<li>Global Scope</li>
<li>Controller Scope</li>
<li>Method Scope</li>
</ol>
<h3 id="heading-binding-using-global-scope"><strong>Binding using Global Scope</strong></h3>
<p>Just like the name “Global” implies, it covers the entirety of a thing – in this case the application. The custom exception filter is <strong>bonded</strong> to the entirety of your web application by using the <code>useGlobalFilters()</code> function. An instance of your custom exception filter gets passed in before starting up the server. </p>
<p>Here is an example of what that looks like:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bootstrap</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> app = <span class="hljs-keyword">await</span> NestFactory.create(AppModule);
  app.useGlobalFilters(<span class="hljs-keyword">new</span> TestExceptionFilter());
  <span class="hljs-keyword">await</span> app.listen(<span class="hljs-number">3000</span>);
}
bootstrap();
</code></pre>
<p>If you bind the exception filter to the global scope, it means that any exceptions of type <code>HttpException</code> thrown from any controller or method within the application will be handled by the <code>TestExceptionFilter</code>.</p>
<h3 id="heading-binding-using-controller-scope"><strong>Binding using Controller Scope</strong></h3>
<p>If you want to handle an exception that not only covers the specific methods in your application but also the entire controller with the methods in it, you can the <code>@UseFilters</code> to bind the custom exception to the controller. Check out the below is example:</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@UseFilters</span>(TestExceptionFilter)
<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'users'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersController {
  <span class="hljs-meta">@Get</span>()
  <span class="hljs-keyword">async</span> findUsers() {
    <span class="hljs-comment">// ...</span>
  }
}
</code></pre>
<p>In this example, the custom exception filter is bonded to the controller by putting it ahead of the <code>@Controller</code> decorator. This way it handles any error that comes from the routes in this controller.</p>
<h3 id="heading-binding-using-method-scope"><strong>Binding using Method Scope</strong></h3>
<p>In this form of binding, you make use of the <code>@UseFilters</code> decorator to apply the Custom ExceptionFilter you defined to a method in your application. Here is an example:</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@Controller</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersController {
  <span class="hljs-meta">@Get</span>()
  <span class="hljs-meta">@UseFilters</span>(TestExceptionFilter)
  <span class="hljs-keyword">async</span> findUsers() {
    <span class="hljs-comment">// ...</span>
  }
}
</code></pre>
<p>In this example, you're using the <code>@UseFilters</code> decorator to bind the <code>TestExceptionFilter</code> exception filter to the <code>findUsers</code> method. This means that if any exception occurs within the <code>findUsers()</code> method, the <code>TestExceptionFilter</code> will catch and handle it.</p>
<h2 id="heading-debugging-made-easier">Debugging Made Easier</h2>
<p>In this tutorial, you learned about exception filters in Nest.js, and how to create custom exception filters. You also saw some different ways in which you can implement them in your applications.</p>
<p>All the methods discussed are good ways to handle exceptions. By implementing these techniques, you can ensure smoother application performance and provide a better user experience.</p>
<p>If you enjoyed reading this article, you can share and follow me on <a target="_blank" href="https://twitter.com/okoyevictorr">Twitter</a> and <a target="_blank" href="https://www.linkedin.com/in/officalrajdeepsingh/">Linkedin</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Upload Files to Azure using NestJS and typeORM with MySQL ]]>
                </title>
                <description>
                    <![CDATA[ Images and videos are examples of huge files that might be stored in your database. And this might impact the performance of your applications because of the amount of space that those files can take up. Also, it expands the database, which makes bac... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/upload-files-to-azure-using-nestjs-and-typeorm-with-mysql/</link>
                <guid isPermaLink="false">66b906bf77c23fa04d7098f5</guid>
                
                    <category>
                        <![CDATA[ Azure ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MySQL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ nestjs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Destiny Erhabor ]]>
                </dc:creator>
                <pubDate>Fri, 21 Oct 2022 23:13:08 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/10/pexels-panumas-nikhomkhai-1148820.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Images and videos are examples of huge files that might be stored in your database. And this might impact the performance of your applications because of the amount of space that those files can take up.</p>
<p>Also, it expands the database, which makes backups larger and slower. Because of this, it's not regarded as a best practice. Instead, using a distributed system to save files and adding a reference to such files to our database is a good choice.</p>
<p>In this article you will learn how to upload these files to Azure cloud distributed services and delete them from Azure using NestJS, a popular Node framework.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-a-cloud-distributed-system">What is a Cloud Distributed System</a>?</p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-azure">What is Azure</a>?</p>
</li>
<li><p><a class="post-section-overview" href="#heading-getting-started">Getting Started</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-connect-to-azure">How to Connect to Azure</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-nestjs-and-mysql-db">How to Set up NestJS and MySQL DB</a></p>
</li>
<li><p><a class="post-section-overview" href="#how-to-connect-to-azure-blob-through-sdk">How to Connect to Azure Blob through SDK</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-upload-the-image-through-the-api">How to Upload the Image through the API</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-an-endpoint-for-uploading-images">How to Create an Endpoint for Uploading Images</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-delete-files">How to Delete Files</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-summary">Summary</a></p>
</li>
</ul>
<h2 id="heading-what-is-a-cloud-distributed-system">What is a Cloud Distributed System?</h2>
<p>A distributed system is made up of a number of independent parts that are spread across several devices. They communicate with one another via messages to accomplish shared objectives.</p>
<p>As a result, to the end user the distributed system will look like a single interface or computer. Together, the system is expected to maximize information and resource usage while preventing errors because, even if one system fails, the service will still be available.</p>
<h2 id="heading-what-is-azure">What is Azure?</h2>
<p>Azure is a platform for public cloud computing that offers solutions for analytics, virtual computing, storage, networking, and much more.</p>
<p>These solutions include Infrastructure as a Service (IaaS), Platform as a Service (PaaS), and Software as a Service (SaaS). You can supplement or replace your on-premise servers with it.</p>
<p>Blobs, tables, and queues are the three main data services provided by Azure. These services are all widely distributed, highly scalable, and reliable. We will be utilizing one of this services in this article.</p>
<h2 id="heading-getting-started">Getting Started</h2>
<p>Before you start following along with this tutorial, make sure you have the following things ready:</p>
<ul>
<li><p>An Azure Subscription – You can <a target="_blank" href="https://azure.microsoft.com/en-us/free/?WT.mc_id=academic-75638-bethanycheum">sign up</a> for a free Azure account if you don’t already have one.</p>
</li>
<li><p>Basic Knowledge and installations of NestJS and MySQL server database. Learn more from the <a target="_blank" href="https://docs.nestjs.com/">NestJS documentation</a>.</p>
</li>
</ul>
<h2 id="heading-how-to-connect-to-azure">How to Connect to Azure</h2>
<p>One of Microsoft's Cloud Storage's cloud-based object storage solution is called a Blob. Large-scale unstructured data storage is best suited for blob storage. Unstructured data, such as text or binary data, is data that does not follow a specific data model or description.</p>
<h3 id="heading-how-to-create-a-blob-storage">How to create a blob storage</h3>
<p><strong>Step 1</strong>: The Azure dashboard is visible once you create an account and log in to the Azure site. Select <code>Storage Accounts</code> from the menu or use the search bar.‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-from-2022-10-15-20-52-47-2.png" alt="creating blob storage step 1‌" width="600" height="400" loading="lazy"></p>
<p><em>Creating blob storage step 1‌</em></p>
<p><strong>Step 2:</strong> Choose <code>create</code> or <code>Create storage account</code> if you do not have an existing storage account from the menu in the following box.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-from-2022-10-15-20-54-28-2.png" alt="creating blob storage step 2" width="600" height="400" loading="lazy"></p>
<p><em>Creating blob storage step 2</em></p>
<p><strong>Step 3:</strong> In this window, we need to fill in subscription, resource group, storage account name, region, performance, and redundancy.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/screencapture-portal-azure-2022-10-15-20_55_56-4.png" alt="creating blob storage step 3" width="600" height="400" loading="lazy"></p>
<p><em>Creating blob storage step 3</em></p>
<ul>
<li><p>The <code>Subscription</code> allows Azure keep track of where to charge for the resource used. You can use your free subscription here.</p>
</li>
<li><p>A <code>resource group</code> is a central grouping for your resource(s). It helps you structure and organize your Azure resources based on your wants.</p>
</li>
<li><p>The <code>Storage account name</code> must be a <strong>unique</strong> name globally.</p>
</li>
<li><p><code>Performance</code> gives you different storage types such as HDD and SSD. Here, we are using Standard.</p>
</li>
<li><p><code>Redundancy</code> helps protect your storage from data center or region failures by duplicating your resource to other regions.</p>
</li>
</ul>
<p><strong>Step 4</strong>: Then click <code>review</code> to validate your options. After completing validation, you can click the <code>Create</code> button to create the Storage account. (Note here that we left every other option as default.)</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-from-2022-10-15-20-59-35-3.png" alt="creating blob storage step 4" width="600" height="400" loading="lazy"></p>
<p><em>Creating blob storage step 4</em></p>
<p>‌When successfully created, the following windows should show up:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/screencapture-portal-azure-2022-10-15-21_01_08-2.png" alt="creating blob storage step 5" width="600" height="400" loading="lazy"></p>
<p><em>Creating blob storage step 5</em></p>
<p><strong>Step 5:</strong> Next, select <code>Go to resource</code> to be sent to the storage account dashboard. The left sidebar is then visible and has a number of options. Choose the <code>containers</code> option there, which is in the Data Storage section.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-from-2022-10-15-21-02-50-3.png" alt="creating blob storage step 5" width="600" height="400" loading="lazy"></p>
<p><em>Creating blob storage step 5</em></p>
<p>‌<strong>Step 6:</strong> in the Containers dashboard, now click on <code>+ Container</code>, then a form will appear on the right side. Fill out the form by giving the <strong>name</strong> and <strong>public access level</strong> (you can use any option according to your requirements) for the container. You can create any number of containers under one storage account</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-from-2022-10-15-21-04-07-3.png" alt="creating blob storage step 6" width="600" height="400" loading="lazy"></p>
<p><em>Creating blob storage step 6</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-from-2022-10-15-21-04-57-2.png" alt="creating blob storage step 6" width="600" height="400" loading="lazy"></p>
<p><em>Creating blob storage step 6</em></p>
<p>Click the create button once you've finished filling out the form.</p>
<p><strong>Step 7:</strong> Copy the Credentials from the Azure portal.</p>
<p>You should have authorization before sending requests to Azure storage. Azure offers two keys for that purpose, each of which contains a connection string. As a result, you will need these credentials as a connection string to the NestJS application.</p>
<p>One of the connection strings is available for copying in the Access keys area of the <code>Security + networking</code> menu on the left. (We will add these to our NestJS .env file.)</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-from-2022-10-15-21-57-01-2.png" alt="creating blob storage step 7" width="600" height="400" loading="lazy"></p>
<p><em>Creating blob storage step 7</em></p>
<p>Cool! You've configured your Azure blob storage. The next step is to setup and link your NestJS application with the blob storage.</p>
<h2 id="heading-how-to-set-up-nestjs-and-mysql-db">How to Set Up NestJS and MySQL DB</h2>
<p>As mentioned earlier, we will be using NestJS as our server and the MySQL database to save a reference to the file saved on the Azure distributed system.</p>
<p>Firstly you need to have NestJS and MySQL server installed on your system. Then run the following NestJS command to start a new project. Let's call our project <code>nestjs-file-upload-azure</code>:</p>
<pre><code class="lang-js">nest <span class="hljs-keyword">new</span> nestjs-file-upload-azure
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-from-2022-10-15-05-18-05-3.png" alt="How to create a new project in nestjs‌" width="600" height="400" loading="lazy"></p>
<p><em>How to create a new project in Nestjs‌</em></p>
<p>Before we get started in creating out resources, let's install the necessary dependencies needed:</p>
<pre><code class="lang-js">yarn add mysql2 @nestjs/typeorm @nestjs/config typeorm
</code></pre>
<p>To setup your MySQL database with NestJS, open the <code>app.module.ts</code> inside the <code>src</code> folder and add the following code:</p>
<pre><code class="lang-javascript">
<span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>; 
<span class="hljs-keyword">import</span> { ConfigModule, ConfigService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/config'</span>; 
<span class="hljs-keyword">import</span> { TypeOrmModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/typeorm'</span>; 
<span class="hljs-keyword">import</span> { FileModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./modules/files/file.module'</span>; 
<span class="hljs-keyword">import</span> { UserModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./modules/users/user.module'</span>; 

@Module({ 
    <span class="hljs-attr">imports</span>: [ 
        ConfigModule.forRoot({ 
            <span class="hljs-attr">envFilePath</span>: <span class="hljs-string">'.env'</span>, 
            <span class="hljs-attr">isGlobal</span>: <span class="hljs-literal">true</span>, 
        }), 
        TypeOrmModule.forRootAsync({ 
            <span class="hljs-attr">imports</span>: [ConfigModule], 
            <span class="hljs-attr">inject</span>: [ConfigService], 
            <span class="hljs-attr">useFactory</span>: <span class="hljs-function">(<span class="hljs-params">config: ConfigService</span>) =&gt;</span> ({ 
                <span class="hljs-attr">type</span>: <span class="hljs-string">'mysql'</span>, 
                <span class="hljs-attr">host</span>: <span class="hljs-string">'localhost'</span>, 
                <span class="hljs-attr">port</span>: <span class="hljs-number">3306</span>, 
                <span class="hljs-attr">username</span>: config.get(<span class="hljs-string">'DB_USERNAME'</span>), 
                <span class="hljs-attr">password</span>: config.get(<span class="hljs-string">'DB_PASSWORD'</span>), 
                <span class="hljs-attr">database</span>: <span class="hljs-string">'azure_upload'</span>, 
                <span class="hljs-attr">entities</span>: [__dirname + <span class="hljs-string">'/**/*.entity{.ts,.js}'</span>], 
                <span class="hljs-attr">synchronize</span>: <span class="hljs-literal">true</span>, 
            }), 
        }), 
        UserModule, 
        FileModule, 
    ], 
    <span class="hljs-attr">controllers</span>: [], 
    <span class="hljs-attr">providers</span>: [], 
}) 

<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppModule</span> </span>{}
</code></pre>
<p>Inside the <code>imports</code>, configure a simple MySQL database with the <code>TypeOrmModule.forRootAsync()</code> called <code>azure_upload</code> locally. It injects <code>ConfigService</code> to allow us to use environment variables (in this case your database name and password).</p>
<p>For a production-based application, you should set <code>synchronize</code> to false and use <code>migration</code> so as to keep your database data safe.</p>
<p>Now the database is connected successfully, thanks to the TypeORM package we installed. You can check by running <code>yarn start:dev</code> on your terminal or <code>npm run start:dev</code> if you are using npm as your package manager.</p>
<h2 id="heading-how-to-connect-to-the-azure-blob-through-sdk">How to Connect to the Azure Blob through SDK</h2>
<p>Using the <code>@azure/storage-blob</code> storage we can connect to Azure. We are still going to need the Multer package for managing file handling operations, and we'll use UUID to generate a unique name for each blob.</p>
<p>Let’s install them first.</p>
<ul>
<li><p><code>yarn add @azure/storage-blob uuidv4 @types/multer</code> or</p>
</li>
<li><p><code>npm install @azure/storage-blob uuidv4 @types/multer</code></p>
</li>
</ul>
<p>Now, let's add the connection string we saved earlier to our <strong>.env</strong> file</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-from-2022-10-15-22-06-39-2.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-upload-the-image-through-the-api">How to Upload the Image through the API</h2>
<p>Since we’ve got the Azure connection set up, we can proceed with uploading our files. For starters, let’s create a file entity and service.</p>
<h3 id="heading-how-to-create-an-azure-service">How to Create an Azure Service</h3>
<p>The Azure service will help us in mapping out the logic to upload, download, and delete files from our Azure storage account we created.</p>
<p>To generate a service, we will use the NestJS CLI. Open the <code>terminal</code> and run <code>nest g service files modules/files --no-spec --flat</code>.</p>
<p>Add the following to the service files generated:</p>
<h6 id="heading-srcmodulesfilesfilesservicets">src/modules/files/files.service.ts</h6>
<pre><code class="lang-javascript">
<span class="hljs-keyword">import</span> { BlobServiceClient, BlockBlobClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'@azure/storage-blob'</span>; 
<span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>; 
<span class="hljs-keyword">import</span> { ConfigService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/config'</span>; 
<span class="hljs-keyword">import</span> { uuid } <span class="hljs-keyword">from</span> <span class="hljs-string">'uuidv4'</span>; 

@Injectable() <span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FilesAzureService</span> </span>{ 
    <span class="hljs-keyword">constructor</span>(private readonly configService: ConfigService) {} 
    private containerName: string; 

    private <span class="hljs-keyword">async</span> getBlobServiceInstance() { 
        <span class="hljs-keyword">const</span> connectionString = <span class="hljs-built_in">this</span>.configService.get(<span class="hljs-string">'CONNECTION_STRING'</span>); 
        <span class="hljs-keyword">const</span> blobClientService = <span class="hljs-keyword">await</span> BlobServiceClient.fromConnectionString( connectionString, ); 
        <span class="hljs-keyword">return</span> blobClientService; 
    } 

    private <span class="hljs-keyword">async</span> getBlobClient(imageName: string): <span class="hljs-built_in">Promise</span>&lt;BlockBlobClient&gt; {
        <span class="hljs-keyword">const</span> blobService = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.getBlobServiceInstance(); 
        <span class="hljs-keyword">const</span> containerName = <span class="hljs-built_in">this</span>.containerName; 
        <span class="hljs-keyword">const</span> containerClient = blobService.getContainerClient(containerName); 
        <span class="hljs-keyword">const</span> blockBlobClient = containerClient.getBlockBlobClient(imageName); 

        <span class="hljs-keyword">return</span> blockBlobClient; 
    } 

    public <span class="hljs-keyword">async</span> uploadFile(file: Express.Multer.File, <span class="hljs-attr">containerName</span>: string) { 
        <span class="hljs-built_in">this</span>.containerName = containerName; 
        <span class="hljs-keyword">const</span> extension = file.originalname.split(<span class="hljs-string">'.'</span>).pop(); 
        <span class="hljs-keyword">const</span> file_name = uuid() + <span class="hljs-string">'.'</span> + extension; 
        <span class="hljs-keyword">const</span> blockBlobClient = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.getBlobClient(file_name);
        <span class="hljs-keyword">const</span> fileUrl = blockBlobClient.url; 
        <span class="hljs-keyword">await</span> blockBlobClient.uploadData(file.buffer); 

        <span class="hljs-keyword">return</span> fileUrl; 
    } 
}
</code></pre>
<p>The private functions create an instance of our Azure blob storage with the connection strings using the azure-sdk methods <code>BlobServiceClient.fromConnectionString()</code>. It also expects the <code>container name</code> we gave our blob container earlier during azure storage creation using <code>getContainerClient</code> and <code>getBlockBlobClient()</code>.</p>
<p>The <code>uploadFile()</code> is a public function that user service can call to make image upload to azure. This function uses the azure instance and the private functions to upload the file and returns the file url.</p>
<h2 id="heading-how-to-create-an-endpoint-for-uploading-images">How to Create an Endpoint for Uploading Images</h2>
<p>It's time to create our user resources that provide an endpoint for us to create (upload) images to Azure, view the image, and delete the image.</p>
<h3 id="heading-how-to-create-a-user-resource">How to Create a User Resource</h3>
<p>The NestJS CLI is a powerful tool that helps scaffold our resource by creating basic component as you know them. To easily create a resource, on the terminal type the following command and follow the prompt for REST APIs:</p>
<pre><code class="lang-js">nest generate resource users modules/users --no-spec --flat
</code></pre>
<p>The <code>--no-spec</code> ignores test files and the <code>--flat</code> creates the resource directly in a <code>modules/users</code> folder.</p>
<p>The above command added the folders <code>dto</code> and <code>entities</code> and files <code>user.controller.ts</code>, <code>user.module.ts</code> and <code>user.service.ts</code> inside the <code>src</code> file. It also performed all necessary updates to sync with <code>app.module.ts</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-from-2022-10-17-22-46-33-2.png" alt="user resources created" width="600" height="400" loading="lazy"></p>
<p><em>User resources created</em></p>
<h3 id="heading-how-to-create-a-user-entity">How to Create a User Entity</h3>
<p>By saving the image URL directly in the database, we can access the public file very quickly.</p>
<h6 id="heading-srcmodulesusersusersentityts">src/modules/users/users.entity.ts</h6>
<pre><code class="lang-javascript">
<span class="hljs-keyword">import</span> { Column, Entity, PrimaryGeneratedColumn } <span class="hljs-keyword">from</span> <span class="hljs-string">'typeorm'</span>; 

@Entity() <span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>{ 
    @PrimaryGeneratedColumn() 
    <span class="hljs-attr">id</span>: number; 

    @Column() 
    <span class="hljs-attr">image_url</span>: string; 
 }
</code></pre>
<h3 id="heading-how-to-create-a-user-service">How to Create a User Service</h3>
<p>The user service helps connect with the database and save the upload image_url, hence the <code>saveUrl()</code> function.</p>
<h6 id="heading-srcmodulesusersusersservicets">src/modules/users/users.service.ts</h6>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>; 
<span class="hljs-keyword">import</span> { InjectRepository } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/typeorm'</span>; 
<span class="hljs-keyword">import</span> { Repository } <span class="hljs-keyword">from</span> <span class="hljs-string">'typeorm'</span>; 
<span class="hljs-keyword">import</span> { User } <span class="hljs-keyword">from</span> <span class="hljs-string">'./entities/user.entity'</span>; 

@Injectable() <span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserService</span> </span>{ 
    <span class="hljs-keyword">constructor</span>( 
        @InjectRepository(User) private readonly userRepository: Repository&lt;User&gt;, 
    ) {} 

    <span class="hljs-keyword">async</span> saveUrl(file_url: string) { 
        <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userRepository.save({ <span class="hljs-attr">image_url</span>: file_url }); 
    } 
}
</code></pre>
<h3 id="heading-how-to-create-a-user-controller">How to Create a User Controller</h3>
<p>This defines the endpoint for a public user to make a file upload. To do that, we follow the <a target="_blank" href="https://docs.nestjs.com/techniques/file-upload">NestJS documentation</a> and use the <code>FileInterceptor</code> that utilizes <a target="_blank" href="https://www.npmjs.com/package/multer"><code>multer</code></a> under the hood.</p>
<h6 id="heading-srcmodulesusersuserscontrollersts">src/modules/users/users.controllers.ts</h6>
<pre><code class="lang-javascript">
<span class="hljs-keyword">import</span> { Controller, Post, UseInterceptors, UploadedFile, } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>; 
<span class="hljs-keyword">import</span> { UserService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./user.service'</span>; 
<span class="hljs-keyword">import</span> { FilesAzureService } <span class="hljs-keyword">from</span> <span class="hljs-string">'../files/file.azure.service'</span>; 
<span class="hljs-keyword">import</span> { FileInterceptor } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/platform-express'</span>;

@Controller(<span class="hljs-string">'user'</span>) <span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span> </span>{ 
    <span class="hljs-keyword">constructor</span>( 
        private readonly userService: UserService, 
        private readonly fileService: FilesAzureService 
    ) {} 

    @Post(<span class="hljs-string">'upload'</span>) 
    @UseInterceptors(FileInterceptor(<span class="hljs-string">'image'</span>)) 
    <span class="hljs-keyword">async</span> create(@UploadedFile() file: Express.Multer.File) { 
        <span class="hljs-keyword">const</span> containerName = <span class="hljs-string">'fileupload'</span>; 
        <span class="hljs-keyword">const</span> upload = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.fileService.uploadFile(file, containerName) 
        <span class="hljs-built_in">this</span>.userService.saveUrl(upload); 
        <span class="hljs-keyword">return</span> { upload, <span class="hljs-attr">message</span>: <span class="hljs-string">'uploaded successfully'</span> } 
    } 
}
</code></pre>
<p>We can test with Postman:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-from-2022-10-16-22-52-06-1.png" alt="Test upload endpoint from postman" width="600" height="400" loading="lazy"></p>
<p><em>Test upload endpoint from Postman</em></p>
<p>And confirm on Azure:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/10/Screenshot-from-2022-10-16-22-50-31-2.png" alt="Confirm image on the azure portal" width="600" height="400" loading="lazy"></p>
<p><em>Confirm image on the Azure portal</em></p>
<h2 id="heading-how-to-delete-files">How to Delete Files</h2>
<p>We also need a means to delete files after submitting them. We'll remove the files from both locations to maintain consistency between our database and Azure storage. Adding the method to the Files Service first:</p>
<p><strong>src/modules/files/files.service.ts</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> deleteFile(file_name: string, <span class="hljs-attr">containerName</span>: string) { 
    <span class="hljs-keyword">try</span> { 
        <span class="hljs-built_in">this</span>.containerName = containerName; 
        <span class="hljs-keyword">const</span> blockBlobClient = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.getBlobClient(file_name);
        <span class="hljs-keyword">await</span> blockBlobClient.deleteIfExists(); 
    } <span class="hljs-keyword">catch</span> (error) { 
        <span class="hljs-built_in">console</span>.log(error); 
    } 
}
</code></pre>
<p>We must now apply it to our Users Service. A crucial addition is that we remove the previous file when a user uploads one while already having one and making an upload endpoint by user id.</p>
<p><strong>src/modules/users/users.service.ts</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { InjectRepository } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/typeorm'</span>;
<span class="hljs-keyword">import</span> { Repository } <span class="hljs-keyword">from</span> <span class="hljs-string">'typeorm'</span>;
<span class="hljs-keyword">import</span> { FilesAzureService } <span class="hljs-keyword">from</span> <span class="hljs-string">'../files/file.azure.service'</span>;
<span class="hljs-keyword">import</span> { User } <span class="hljs-keyword">from</span> <span class="hljs-string">'./entities/user.entity'</span>;

@Injectable()
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserService</span> </span>{
  <span class="hljs-keyword">constructor</span>(
    @InjectRepository(User) private readonly userRepository: Repository&lt;User&gt;,
    private readonly fileService: FilesAzureService,
  ) {}

  <span class="hljs-keyword">async</span> saveUrl(id, <span class="hljs-attr">file_url</span>: string, <span class="hljs-attr">containerName</span>: string): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-keyword">void</span>&gt; {
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userRepository.findOne({
      <span class="hljs-attr">where</span>: { id },
    });
    <span class="hljs-keyword">const</span> file_image = user?.image_url;
    <span class="hljs-keyword">let</span> getfile = <span class="hljs-string">''</span>;

    <span class="hljs-keyword">if</span> (file_image) {
      getfile = file_image.split(<span class="hljs-string">'/'</span>).pop();
    }
    <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userRepository.save({
      ...user,
      <span class="hljs-attr">image_url</span>: file_url,
    });
    <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.fileService.deleteFile(getfile, containerName);
  }

  <span class="hljs-keyword">async</span> getimage(id: number): <span class="hljs-built_in">Promise</span>&lt;any&gt; {
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userRepository.findOne({
      <span class="hljs-attr">where</span>: { id },
    });

    <span class="hljs-keyword">return</span> user;
  }

  <span class="hljs-keyword">async</span> remove(id: number, <span class="hljs-attr">containerName</span>: string): <span class="hljs-built_in">Promise</span>&lt;User&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userRepository.findOne({
        <span class="hljs-attr">where</span>: { id },
      });
      <span class="hljs-keyword">const</span> file_url = user?.image_url;
      <span class="hljs-keyword">if</span> (file_url) {
        <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userRepository.update(id, {
          ...user,
          <span class="hljs-attr">image_url</span>: <span class="hljs-string">''</span>,
        });

        <span class="hljs-keyword">const</span> file_ = file_url.split(<span class="hljs-string">'/'</span>).pop();

        <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.fileService.deleteFile(file_, containerName);
      }

      <span class="hljs-keyword">return</span> user;
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.log(error);
      <span class="hljs-keyword">return</span> error;
    }
  }
}
</code></pre>
<p>Including an endpoint where users can send an image is the final component. To accomplish that, we use the <code>FileInterceptor</code>, which internally makes use of <code>multer</code>, in accordance with the NestJS documentation.</p>
<p><strong>src/modules/users/users.controller.ts</strong></p>
<pre><code class="lang-javascript">Controller(<span class="hljs-string">'user'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span> </span>{
  <span class="hljs-keyword">constructor</span>(
    private readonly userService: UserService,
    private readonly fileService: FilesAzureService
  ) {}

  @Post(<span class="hljs-string">'/:id/upload'</span>)
  @UseInterceptors(FileInterceptor(<span class="hljs-string">'image'</span>))
  <span class="hljs-keyword">async</span> create(@UploadedFile() file: Express.Multer.File, @Param(<span class="hljs-string">'id'</span>) id) {
    <span class="hljs-keyword">const</span> containerName = <span class="hljs-string">'fileupload'</span>;
    <span class="hljs-keyword">const</span> upload = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.fileService.uploadFile(file, containerName)
    <span class="hljs-built_in">this</span>.userService.saveUrl(id, upload, containerName);
    <span class="hljs-keyword">return</span> {
      upload,
      <span class="hljs-attr">message</span>: <span class="hljs-string">'uploaded successfully'</span>
    }
  }

  @Get(<span class="hljs-string">'/:id'</span>)
  <span class="hljs-keyword">async</span> getimage(@Param(<span class="hljs-string">'id'</span>) id) {
    <span class="hljs-keyword">const</span> image = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userService.getimage(id);
    <span class="hljs-keyword">return</span> {
      image,
      <span class="hljs-attr">message</span>: <span class="hljs-string">'get image successfully'</span>
    }
  }

  @Delete(<span class="hljs-string">'remove/:id'</span>)
  @UseInterceptors(FileInterceptor(<span class="hljs-string">'image'</span>))
  <span class="hljs-keyword">async</span> remove(@UploadedFile() file: Express.Multer.File , @Param(<span class="hljs-string">'id'</span>) id) {
    <span class="hljs-keyword">const</span> containerName = <span class="hljs-string">'fileupload'</span>;
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userService.remove(id, containerName);
    <span class="hljs-keyword">return</span> {
      user,
      <span class="hljs-attr">message</span>: <span class="hljs-string">'deleted successfully'</span>
    }
  }
}
</code></pre>
<p>These sync with your Azure storage to delete unused file uploads.</p>
<p>You can find the <a target="_blank" href="https://github.com/Caesarsage/nest-file-upload-azure">full code repository Link on <strong>GitHub</strong></a><strong>.</strong></p>
<h2 id="heading-cleaning-up">Cleaning Up</h2>
<p>To avoid paying for the underlying Azure storage cost, you should clean up your resources if they're not being used.</p>
<p>To clean up your Azure resources, in the Azure portal go to or search for resources group, find the one you just created, and delete it. This will delete all resources in the resource group.</p>
<h2 id="heading-summary">Summary</h2>
<p>In this article, we've learnt the fundamentals of Azure Blob storage and how to use it in our NestJS API.</p>
<p>To accomplish that, we've given the required credentials to Azure SDK, and as a result, we've been able to upload and remove files to Azure.</p>
<p>To track our files, we've also kept our MySQL database synchronized with an Azure blob container. We used the FileInterceptor, which is powered by Multer, to upload files using the API.</p>
<p>As always, I hope you enjoyed the article and learned something new. If you want, you can also follow me on <a target="_blank" href="https://www.linkedin.com/in/destiny-erhabor">LinkedIn</a> or <a target="_blank" href="https://twitter.com/caesar_sage">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
