<?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[ Abimbola Adedotun Samuel - 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[ Abimbola Adedotun Samuel - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 16:29:52 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/Dotcodes/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <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>
        
    </channel>
</rss>
