<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: rutvikjani</title>
    <description>The latest articles on DEV Community by rutvikjani (@rutvikjani).</description>
    <link>https://dev.to/rutvikjani</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1067314%2Ffee8afb1-2ec3-484c-884a-d1805b588d4b.png</url>
      <title>DEV Community: rutvikjani</title>
      <link>https://dev.to/rutvikjani</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rutvikjani"/>
    <language>en</language>
    <item>
      <title>How To install feed from your live stream in node-media-server.</title>
      <dc:creator>rutvikjani</dc:creator>
      <pubDate>Fri, 08 Dec 2023 06:20:06 +0000</pubDate>
      <link>https://dev.to/rutvikjani/how-to-install-feed-from-your-live-stream-in-node-media-server-pop</link>
      <guid>https://dev.to/rutvikjani/how-to-install-feed-from-your-live-stream-in-node-media-server-pop</guid>
      <description>&lt;h2&gt;
  
  
  Introduction:
&lt;/h2&gt;

&lt;p&gt;In the dynamic world of digital content, live streaming has emerged as a powerful and engaging way to connect with audiences in real-time. Whether you're a content creator, educator, or simply someone looking to share experiences as they happen, setting up a reliable live streaming infrastructure is crucial. In this comprehensive guide, we'll walk you through the process of creating a Node Media Server, seamlessly pushing your live stream with FFmpeg, and even show you how to download the feed in the widely used HLS (HTTP Live Streaming) format.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Node.js : Make Sure to install the node.js in your system. If you do not already installed node.js then you can download from the link - &lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;a href="https://nodejs.org/en/download" rel="noopener noreferrer"&gt;
      nodejs.org
    &lt;/a&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;FFmpeg : Download the FFmpeg module in your pc. You can download FFmpeg from - &lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;a href="https://ffmpeg.org/download.html" rel="noopener noreferrer"&gt;
      ffmpeg.org
    &lt;/a&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Modules Used
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Node-Media-Server &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Node Media Server (NMS) is a powerful and extensible media server built on top of Node.js, a server-side JavaScript runtime. Developed to meet the demands of modern live streaming applications, NMS provides support for various streaming protocols, including Real-Time Messaging Protocol (RTMP), HTTP Live Streaming (HLS), and more.&lt;/p&gt;

&lt;p&gt;You can download through vscode terminal by following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install node-media-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;fluent-ffmpeg &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;fluent-ffmpeg is a Node.js module that provides a fluent interface for working with FFmpeg. It allows developers to use FFmpeg capabilities in a more user-friendly and JavaScript-oriented manner, making it easier to construct complex multimedia processing pipelines.&lt;/p&gt;

&lt;p&gt;You can download through vscode terminal by following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; npm install fluent-ffmpeg 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Moment&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Moment.js is a lightweight and versatile JavaScript library for parsing, validating, manipulating, and formatting dates and times. It simplifies working with dates in JavaScript, providing a consistent and user-friendly API for various date-related operations.&lt;/p&gt;

&lt;p&gt;You can download through vscode terminal by following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; npm install moment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now We are all set to start our node-media-server project.&lt;/p&gt;

&lt;p&gt;Step 1 : Configure our node-media-server.&lt;/p&gt;

&lt;p&gt;First you need to import the node-media-server. By using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const nms = require('node-media-server)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we need to write the configurations for node-media server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; const config = {
  rtmp: {
    port: 1935,
    chunk_size: 60000,
    gop_cache: true,
    ping: 60,
    ping_timeout: 30,
  },
  http: {
    port: 8000,
    mediaroot: "./media",
    allow_origin: "*",
  },
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are the basic configurations for rtmp(real time messaging protocol) feed and hls(http live streaming) feed. The rtmp configs contains of the -&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;port&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;port number &lt;strong&gt;1935&lt;/strong&gt; which is by default port number. You can change it to the available port number.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;chunk_size&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This parameter represents the size of the data chunks that will be used during streaming. Here, it is set to 60000 bytes. &lt;br&gt;
Here, &lt;strong&gt;chunk_size: 60000&lt;/strong&gt; indicates that the server will use a chunk size of 60,000 bytes for RTMP streaming. Adjusting this value allows you to fine-tune the trade-off between latency, efficiency, and other factors based on the specific requirements of your streaming application. Different streaming platforms or protocols may have their own guidelines or default values for chunk sizes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;gop_cache&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Group of Pictures (GOP) is a key concept in video compression. It represents a group of consecutive frames in a video stream where the inter-frame compression is applied. The GOP structure typically consists of three types of frames: I-frames (keyframes), P-frames (predicted frames), and B-frames (bidirectional frames).&lt;/p&gt;

&lt;p&gt;Setting gop_cache to true in the context of an RTMP server, such as with the configuration for node-media-server, means that the server will cache GOP frames. Caching GOP frames can have several benefits: Improved Seeking Performance, Reduce Bandwidth Usage, Stability in Video Playback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ping&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It sets the interval for sending ping messages to clients, in seconds. Here, it's set to 60 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ping_timeout&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The timeout duration for ping responses from clients, in seconds. If a client doesn't respond within this timeout, it may be considered disconnected. Here, it's set to 30 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;http&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This configurations is for http live streaming it contains of -&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;port&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here also the port number is by default set to 8000 and we can change it as per our requirements&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;mediaroot&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is set to "./media" that means it indicates that the media files are expected to be located in the "./media" directory. The media server will serve content from this directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For example&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;if you have a file named "video.mp4" in the "./media" directory, it would be accessible through the media server at a URL like &lt;a href="http://localhost:8000/video.mp4"&gt;http://localhost:8000/video.mp4&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, the mediaroot setting allows you to define the base directory where your media files are stored, and the media server uses this information to serve content to clients or to incorporate it into a streaming workflow. This setting is crucial for the media server to know where to look for and serve media files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;allow_origin&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It defines the value of the Access-Control-Allow-Origin header, which controls which domains can make requests to the server. Here, it's set to "*" which means any domain is allowed.&lt;/p&gt;

&lt;p&gt;Now we need to make an instance of the node-media-server -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const nms = new NodeMediaServer(config);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our node-media-server is set and now the second step is to download the feed on specific time-interval.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step : 2&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Take your static live url in a variable and set the directory in which you want to save your feed recordings -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const inputURL = "Your RTMP url";
const outputDir = "./output/"; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now further going ahead check for the directory if it is already exist or not :-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (!fs.existsSync(outputDir)) {
  fs.mkdirSync(outputDir);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here the "fs"(file streaming) is an inbuilt module of node.js you only need to import it in your file :-&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step : 3&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Make a function which will save our recordings in our repository -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  function saveStream() {
  const epochTime = moment().format("HH_mm_ss");
  const outputFilename = `${outputDir}${epochTime}.m3u8`;

  ffmpeg(inputURL)
    .inputFormat("flv")
        .outputOptions([
        `-hls_segment_filename ${tsFileName}.ts`,        
        // "-hls_time 900",
        "-hls_time 30",
        "-hls_list_size 5",
        // "-t 900",
        "-t 30",
        "-f hls",
        ])
    .output(outputFilename)
    .on("end", () =&amp;gt; {
      console.log(`Saved stream to ${outputFilename}`);
    })
    .on("error", (err) =&amp;gt; {
      console.error("Error:", err);
    })
    .run();
}

saveStream();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function will save our rtmp feed to our directory this function is simple. Firslty, we take the time when the streaming starts and make our recording file name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const epochTime = moment().format("HH_mm_ss");
  const outputFilename = `${outputDir}${epochTime}.m3u8`;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we take the rtmp url and save it in the hls format using fluent ffmpeg module :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ffmpeg(inputURL)
    .inputFormat("flv")
    .outputOptions([
        "-hls_time 25",   
        "-hls_list_size 5",
        "-t 30",       
        "-f hls",
    ])
    .output(outputFilename)
    .on("end", () =&amp;gt; {
      console.log(`Saved stream to ${outputFilename}`);
    })
    .on("error", (err) =&amp;gt; {
      console.error("Error:", err);
    })
    .run();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this whole code will take the rtmp url and then it will convert it into hls format. The output format contains : &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;hls_time&lt;/strong&gt; - Sets the duration of each segment in the HLS playlist to 25 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;hls_list_size&lt;/strong&gt; - Sets the maximum number of playlist entries (segments) to 5.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;-t 30&lt;/strong&gt; - Set the duration of the feed which is getting saved(in seconds)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;-f hls&lt;/strong&gt; - It is specifying the output format as hls&lt;/p&gt;

&lt;p&gt;Then we are saving the processed file in our directory with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; .output(outputFilename)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Final part of the function is Event Handling when our processed output is getting saved in our file then it will give us a log otherwise it will throw an error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.on("end", () =&amp;gt; {
      console.log(`Saved stream to ${outputFilename}`);
    })
    .on("error", (err) =&amp;gt; {
      console.error("Error:", err);
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly Executing our ffmpeg command with -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.run()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After setting everything call the function and set the interval as per your requirements I set it on the 30sec of interval. (to save the memory give the interval as same as your output file duration)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;saveStream();

setInterval(saveStream, 30000);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, Handle event of post publish. Post publish will trigger when the stream is starting on node-media-server. Here I gave a condition because I am giving static URL -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nms.on('postPublish', (_, streamPath, _params) =&amp;gt; {
  if (streamPath.endsWith('1efa24f9-0cd0-47c5-b604-c7e3ee118302')) {
    saveStream();
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, Everything is all set now we can run our instance of node-meda-server so that it can run our script. From this our node-media-server will run.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nms.run();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our final code will something like this -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const NodeMediaServer = require("node-media-server");
const fs = require("fs");
const moment = require('moment')
const ffmpeg = require("fluent-ffmpeg");

const config = {
  rtmp: {
    port: 1935,
    chunk_size: 60000,
    gop_cache: true,
    ping: 60,
    ping_timeout: 30,
  },
  http: {
    port: 8000,
    mediaroot: "./media",
    allow_origin: "*",
  },
};

const nms = new NodeMediaServer(config);

const inputURL =
  "rtmp://media5.ambicam.com:1938/live/1efa24f9-0cd0-47c5-b604-c7e3ee118302";
const outputDir = "./output/";

if (!fs.existsSync(outputDir)) {
  fs.mkdirSync(outputDir);
}

function saveStream() {
  const epochTime =  moment().format("HH_mm_ss"); 
  const outputFilename = `${outputDir}${epochTime}.m3u8`;

  ffmpeg(inputURL)
    .inputFormat("flv")
    .outputOptions([
        "-hls_time 25",   
        "-hls_list_size 5",
        "-t 30",       
        "-f hls",
    ])
    .output(outputFilename)
    .on("end", () =&amp;gt; {
      console.log(`Saved stream to ${outputFilename}`);
    })
    .on("error", (err) =&amp;gt; {
      console.error("Error:", err);
    })
    .run();
}

saveStream();

setInterval(saveStream, 30000);

nms.on('postPublish', (_, streamPath, _params) =&amp;gt; {
  if (streamPath.endsWith('1efa24f9-0cd0-47c5-b604-c7e3ee118302')) {
    saveStream();
  }
});

nms.run();

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this tutorial, we embarked on a journey to set up a basic Node Media Server (NMS) instance, catering to beginners in the realm of video streaming. We covered the essentials from installing the node-media-server package to configuring a simple server instance capable of handling video streams.&lt;/p&gt;

&lt;p&gt;One of the highlights of our exploration was the introduction of a straightforward mechanism to save video feeds at specific time intervals. This feature adds an extra layer of functionality to your streaming setup, enabling you to capture and store your content for future reference or archival purposes.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>mediaserver</category>
      <category>nodemediaserver</category>
      <category>node</category>
    </item>
    <item>
      <title>Creating API with Nest.js and MongoDB.</title>
      <dc:creator>rutvikjani</dc:creator>
      <pubDate>Sun, 16 Jul 2023 08:02:29 +0000</pubDate>
      <link>https://dev.to/rutvikjani/creating-api-with-nestjs-and-mongodb-28k1</link>
      <guid>https://dev.to/rutvikjani/creating-api-with-nestjs-and-mongodb-28k1</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this blog post, I will share my experience building a comprehensive and well-defined e-commerce API using NestJS, MongoDB, and Postman.&lt;/p&gt;

&lt;p&gt;The API I built includes several endpoints that collectively make up a complete e-commerce API. These endpoints are for admins, end users, products, and categories.&lt;/p&gt;

&lt;p&gt;Each endpoint is well-defined and provides a clear and concise interface for interacting with the API. The endpoints are also well-documented, making it easy for developers to understand how to use them.&lt;/p&gt;

&lt;p&gt;I hope this blog post will be helpful to other developers who are interested in building e-commerce APIs with NestJS.&lt;/p&gt;

&lt;p&gt;Here are some of the key takeaways from this project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NestJS&lt;/strong&gt; is a powerful framework that can be used to build comprehensive and well-defined APIs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MongoDB&lt;/strong&gt; is a reliable and scalable database that is well-suited for e-commerce applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Postman&lt;/strong&gt; is a powerful tool for testing and debugging APIs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I encourage you to try building your own e-commerce API using NestJS, MongoDB, and Postman. It is a great way to learn about these technologies and build a valuable skill set.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;About Project&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Ecommerce systems typically have two types of users: users and admins. Users can register and login to the system, but they can only read products. Admins can register, login, and perform CRUD operations on products.&lt;/p&gt;

&lt;p&gt;The password hashing for both users and admins is done with the bcrypt module in npm. This module provides a secure way to hash passwords.&lt;/p&gt;

&lt;p&gt;Product categories are defined with the help of the .populate() method. This method allows you to fetch the product categories from the database when you fetch a product. This makes it easy to display the product categories on the product page.&lt;/p&gt;

&lt;p&gt;Detailed Explaination :- &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users and admins: Users are the end users of the ecommerce system. They can register and login to the system, and they can view products. Admins are system administrators. They have more privileges than users, and they can perform CRUD operations on products.&lt;/li&gt;
&lt;li&gt;Password hashing: Password hashing is a security measure that helps to protect user passwords. When a user registers for an ecommerce system, their password is hashed using a secure algorithm. This means that the password is not stored in plain text, and it cannot be easily decoded.&lt;/li&gt;
&lt;li&gt;jsonwebtoken module: The jsonwebtoken module is a popular module for generating and verifying JSON Web Tokens (JWTs). JWTs are a secure way to authenticate users. When a user logs in to an ecommerce system, they are issued a JWT. This JWT can then be used to authenticate the user on subsequent requests.&lt;/li&gt;
&lt;li&gt;.populate() method: The .populate() method is a method that is used to fetch related documents from the database. In the context of ecommerce systems, the .populate() method can be used to fetch product categories when a product is fetched. This makes it easy to display the product categories on the product page.&lt;/li&gt;
&lt;li&gt;bcrypt module: The bcrypt module uses the bcrypt algorithm to hash passwords. The bcrypt algorithm is a slow algorithm, which makes it difficult for attackers to brute-force passwords. The bcrypt module also uses a salt, which is a random string that is added to the password before it is hashed. This makes the hash more unique and difficult to crack.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How to create Nest Project&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;First of all we need to install Nestjs in our root directory. To install Nestjs Cli in our root directory we need to follow the command:-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$npm i -g @nestjs/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Moreover, for creating boilerplate for our nest project file We need to write following code:-&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$nest new project-name 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Your created file will look like this :- &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qQHVwUWY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5tsvtlz2l0tcgvlkp9ip.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qQHVwUWY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5tsvtlz2l0tcgvlkp9ip.PNG" alt="Image description" width="293" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your project file will look like this at first but you can create or delete folders as per your requirement.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Creating first API&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Nest APIs are made up of three main components: providers, controllers, and services.&lt;/p&gt;

&lt;p&gt;Providers are plain JavaScript classes that provide functionality to the application. They are declared in module files.&lt;/p&gt;

&lt;p&gt;Controllers handle HTTP requests. They are responsible for routing requests to the appropriate providers and services.&lt;/p&gt;

&lt;p&gt;Services contain the business logic of the application. They are used by controllers to perform tasks such as data access and manipulation.&lt;/p&gt;

&lt;p&gt;In other words, providers are the foundation of an API, controllers are the glue that holds it together, and services are the muscle that makes it work.&lt;/p&gt;

&lt;p&gt;The normal flow of data is like....&lt;br&gt;
&lt;strong&gt;Controller -&amp;gt; Service;&lt;br&gt;
Service -&amp;gt; Repository/Schema;&lt;br&gt;
Repository/Schema -&amp;gt; Database;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So here's how your all your files inside src folder will look like...&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Schema&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose";
import { Document } from "mongoose";

@Schema()
export class Admin extends Document{

    @Prop({required: true})
    firstName: string

    @Prop({required: true})
    lastName: string

    @Prop({unique: true, required: true })
    userName: string

    @Prop({required: true})
    password: string

    @Prop({ unique: true, required: true })
    mobileNo : number

    @Prop({ unique: true, required: true })
    email: string

    @Prop({required: true})
    gender: string

    @Prop()
    isAdmin: boolean
}
 export const AdminSchema = SchemaFactory.createForClass(Admin)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The code above defines a mongoose schema for the admin API. A schema is a blueprint for a document in a MongoDB database. It defines the structure of the document, including the fields that are allowed and the types of data that can be stored in each field.&lt;/p&gt;

&lt;p&gt;The mongoose schema in the code above uses decorators to validate the data that is stored in the document. For example, the IsString() decorator ensures that the value of the name field is a string, and the IsNotEmpty() decorator ensures that the value of the email field is not empty.&lt;/p&gt;

&lt;p&gt;This schema ensures that the data that is stored in the admin API is valid and consistent. This makes it easier to manage the data and to ensure that the API is working correctly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Controllers&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Body, Controller, Post } from '@nestjs/common';
import { adminService } from './admin.service';
import { Admin } from './admin.schema';
import { adminDto } from './dto/admin.dto';
import { adminLoginDto } from './dto/adminLogin.dto';

@Controller('admin')
export class adminController {

  constructor(
    private adminService: adminService, 
    ) {}

  @Post('/register')
  async newAdmin(@Body() adminDto: adminDto): Promise&amp;lt;Admin | object&amp;gt; {
    return this.adminService.newAdmin(adminDto);
  }

  @Post('/login')
  async loginAdmin(@Body() adminLoginDto: adminLoginDto): Promise&amp;lt;object&amp;gt;{
   return this.adminService.loginAdmin(adminLoginDto);
  }
}

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

&lt;/div&gt;


&lt;p&gt;The code above shows the Admin API controller file, which is a class that handles HTTP requests and responses for managing admin users. The controller uses only the HTTP POST method for signup and login requests. It also uses the services, as mentioned above, which are classes that provide business logic.&lt;/p&gt;

&lt;p&gt;To create a controller file, it is mandatory to use the @Controller() decorator above the controller class. This is a Spring annotation that marks a class as a controller.&lt;/p&gt;

&lt;p&gt;The term DTO stands for Data Transfer Object. DTOs are simple objects that are used to transfer data between different components of an application. In this case, they are used to validate data that is flowing in incoming requests.&lt;/p&gt;

&lt;p&gt;Here is the Example of a Simple admin login Dto....&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { IsString } from 'class-validator';

export class adminLoginDto {
  @IsString()
  userName: string;

  @IsString()
  password: string;

}

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

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Services&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* eslint-disable prettier/prettier */
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { Admin } from './admin.schema';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import * as bcrypt from 'bcrypt';
import { adminDto } from './dto/admin.dto';
import { JwtService } from '@nestjs/jwt';
import { adminLoginDto } from './dto/adminLogin.dto';

@Injectable()
export class adminService {
  constructor(
    @InjectModel(Admin.name)
    private adminModel: Model&amp;lt;Admin&amp;gt;,
    private jwtService: JwtService,
  ) {}

  async newAdmin(adminDto: adminDto): Promise&amp;lt;Admin | object&amp;gt; {
    const {
      firstName,
      lastName,
      userName,
      password,
      email,
      mobileNo,
      gender,
      isAdmin,
    } = adminDto;

    const salt = await bcrypt.genSalt();
    const hashedPassword = await bcrypt.hash(password, salt);

    const existingUser = await this.adminModel.findOne({
      userName,
      email,
    });
    if (!existingUser) {
      const adminUser = await this.adminModel.create({
        firstName,
        lastName,
        userName,
        password: hashedPassword,
        email,
        mobileNo,
        gender,
        isAdmin: true,
      });
      return adminUser.save();
    } else {
      return {
        statusCode: 400,
        message: `User already exist.`,
      };
    }
  }

  async loginAdmin(adminLoginDto: adminLoginDto): Promise&amp;lt;object&amp;gt; {
    const { userName, password } = adminLoginDto;
    const admin = await this.adminModel.findOne({ userName });
    const isAdmin = admin.isAdmin;
    if (admin &amp;amp;&amp;amp; (await bcrypt.compare(password, admin.password))) {
      const payload = { userName, isAdmin };
      const accessToken = await this.jwtService.sign(payload);
      return {
        statusCode: 200,
        message: 'Login Successfull',
        Admin: admin,
        token: accessToken,
      };
    } else {
      throw new UnauthorizedException('User is not authorized');
    }
  }
}


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

&lt;/div&gt;


&lt;p&gt;The Services module in a Nest project is responsible for the business logic of the application. It is used by the controller modules to perform tasks such as saving data to the database, verifying passwords, and generating tokens.&lt;/p&gt;

&lt;p&gt;In this module, we are saving the admin's data on sign-in with hashed passwords using the bcrypt package. This ensures that the passwords are stored securely and cannot be easily decoded.&lt;/p&gt;

&lt;p&gt;The .findOne() method is used to find data in the database based on the username and email fields. These two fields should be unique, so using the .findOne() method ensures that we only return one record.&lt;/p&gt;

&lt;p&gt;Array destructuring is used to extract the required fields from the record that we retrieved from the database. These fields will be saved into our database. We also keep a flag to differentiate between end-users and admin users.&lt;/p&gt;

&lt;p&gt;The Login function uses the same .findOne() method to find the data from the database. The password is then verified, and if the credentials are correct, the user will receive a token.&lt;/p&gt;

&lt;p&gt;The AuthGuard that we used will only give access to the admin to create, delete, and update products. End-users do not have the same authority as the admin.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this blog post, we discussed the process of creating an admin API for an e-commerce platform. We covered the different endpoints that are typically included in an admin API, as well as the different constraints that you will need to consider when creating an API.&lt;/p&gt;

&lt;p&gt;We also discussed the need for additional APIs, such as end-user, product, and category APIs, in order to provide a complete e-commerce experience to users. We briefly touched on the different constraints that you will need to consider when creating these additional APIs.&lt;/p&gt;

&lt;p&gt;We hope that this blog post has been helpful. If you have any questions, please feel free to leave a comment below.&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

&lt;p&gt;Here You can checkout my full project, I tried to keep it as minimal as possible for better understanding..&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/rutvikjani"&gt;
        rutvikjani
      &lt;/a&gt; / &lt;a href="https://github.com/rutvikjani/Ecommerce-Api-Using-Nestjs-MongoDB"&gt;
        Ecommerce-Api-Using-Nestjs-MongoDB
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
    </item>
  </channel>
</rss>
