<?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>Forem: Funmi Olaiya</title>
    <description>The latest articles on Forem by Funmi Olaiya (@feobaby).</description>
    <link>https://forem.com/feobaby</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%2F332710%2Ff3465467-c76e-49bd-99a9-d8b061cf36f3.png</url>
      <title>Forem: Funmi Olaiya</title>
      <link>https://forem.com/feobaby</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/feobaby"/>
    <language>en</language>
    <item>
      <title>Get started with NestJS and create a todo "notes" app: documenting the API endpoints with NestJs swagger (Part 3)</title>
      <dc:creator>Funmi Olaiya</dc:creator>
      <pubDate>Sat, 09 May 2020 09:44:35 +0000</pubDate>
      <link>https://forem.com/feobaby/get-started-with-nestjs-and-create-a-todo-notes-app-documenting-the-api-endpoints-with-nestjs-swagger-part-3-67</link>
      <guid>https://forem.com/feobaby/get-started-with-nestjs-and-create-a-todo-notes-app-documenting-the-api-endpoints-with-nestjs-swagger-part-3-67</guid>
      <description>&lt;p&gt;Hey, &lt;/p&gt;

&lt;p&gt;Nice to see you here again, if you have been following these series from the beginning,&lt;/p&gt;

&lt;p&gt;For the part1: &lt;a href="https://dev.to/funmi5/get-started-with-nestjs-and-create-a-todo-notes-app-4c67"&gt;https://dev.to/funmi5/get-started-with-nestjs-and-create-a-todo-notes-app-4c67&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wrote about how to create a todo app with Nestjs and why I would consider the NestJs framework for future projects.&lt;/p&gt;

&lt;p&gt;For the part2: &lt;a href="https://dev.to/funmi5/get-started-with-nestjs-and-create-a-todo-notes-app-creating-e2e-tests-part-2-5pl"&gt;https://dev.to/funmi5/get-started-with-nestjs-and-create-a-todo-notes-app-creating-e2e-tests-part-2-5pl&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wrote on how to create end-to-end tests using the inbuilt &lt;code&gt;Testing module&lt;/code&gt; of NestJs.&lt;/p&gt;

&lt;p&gt;Now, this article will be the last part of the series and we will learn how to document the API endpoints we have built earlier using the inbuilt &lt;code&gt;swagger module&lt;/code&gt; of NestJs.&lt;/p&gt;




&lt;p&gt;Let's get started:&lt;/p&gt;

&lt;p&gt;Originally, I do not use Swagger to document an API endpoint I work on, I prefer &lt;strong&gt;Apiary/API Blueprint&lt;/strong&gt; because of the user interface, simplicity and the fact that it is easy to set up using the JSON format.&lt;/p&gt;

&lt;p&gt;But alas, NestJs is different, you can document an API as you are building, everything syncs together with the code. Isn't that great?!&lt;/p&gt;




&lt;p&gt;Install the following command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The package will allow us to use configure and use the swagger module.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @nestjs/swagger swagger-ui-express -S
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have to configure and initialize swagger in the &lt;code&gt;main.ts&lt;/code&gt; file&lt;/p&gt;

&lt;p&gt;Modify the file to the 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;import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from "@nestjs/swagger";
import { NoteModule } from "../src/modules/note.module";

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.setGlobalPrefix("api/v1");

  const options = new DocumentBuilder()
    .setTitle("Notes todo app")
    .setDescription(
      "A documentation for notes"
    )
    .setVersion("1.0")
    .addTag("Notes")
    .build();
  const apppDocument = SwaggerModule.createDocument(app, options, {
    include: [NoteModule]
  });
  SwaggerModule.setup("api", app, apppDocument);
  await app.listen(3000);
}
bootstrap();

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;DocumentBuilder()&lt;/code&gt; helps to structure a document that takes in different properties for configuration.&lt;/li&gt;
&lt;li&gt;Read more and extensively here: &lt;a href="https://docs.nestjs.com/recipes/swagger#openapi-swagger" rel="noopener noreferrer"&gt;https://docs.nestjs.com/recipes/swagger#openapi-swagger&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, the data-transfer-object(dto) has to be configured:&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;note.dto.ts&lt;/code&gt; file, modify it to the 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;import { ApiProperty } from "@nestjs/swagger";

export class CreateNoteDTO {
    @ApiProperty()
    name: string;

    @ApiProperty()
    description: string;

    @ApiProperty()
    tags: string;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;to annotate all Api properties, the &lt;code&gt;@ApiProperty&lt;/code&gt; decorator is used.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;The controllers have to be modified too, to the 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;import { Controller, Res, HttpStatus, Post, Get, Param, Body, Patch, Query, Delete } from "@nestjs/common";
import { NoteService } from "../services/note.service";
import { CreateNoteDTO } from "../dtos/note.dto";
import { ApiResponse, ApiTags } from "@nestjs/swagger";

@ApiTags("Notes")
@Controller('note')
export class NoteController {
    constructor(private noteService: NoteService) { }

    @ApiResponse({ status: 201 })
    @Post('/add')
    async createANote(@Res() res, @Body() createNoteDTO: CreateNoteDTO) {
        const note = await this.noteService.createANote(createNoteDTO);
        return res.status(HttpStatus.CREATED).json({
            status: 201,
            message: "Successful!",
            data: note
        })
    }

    @ApiResponse({ status: 200 })
    @Get('/all')
    async getAllNotes(@Res() res) {
        const notes = await this.noteService.getAllNotes();
        return res.status(HttpStatus.OK).json({
            status: 200,
            data: notes
        })
    }

    @ApiResponse({ status: 200 })
    @Get("/:noteId")
    async getANote(@Res() res, @Param("noteId") _id: string) {
        const note = await this.noteService.getANote(_id);
        if (!note)
            return res
                .status(HttpStatus.NOT_FOUND)
                .json({ status: 404, error: "Not found!" });
        return res.status(HttpStatus.OK).json({ status: 200, data: note });
    }

    @ApiResponse({ status: 200 })
    @Patch('/update/:noteId')
    async updateCustomer(@Res() res, @Body() createNoteDTO: CreateNoteDTO, @Param("noteId") _id: string) {
        const note = await this.noteService.updateANote(_id, createNoteDTO);
        if (!note)
            return res
                .status(HttpStatus.NOT_FOUND)
                .json({ status: 404, error: "Not found!" });
        return res.status(HttpStatus.OK).json({
            status: 200,
            message: 'Successful!',
            note
        });
    }

    @ApiResponse({ status: 200 })
    @Delete('/delete/:noteId')
    async deleteCustomer(@Res() res, @Param('noteId') _id) {
        const note = await this.noteService.deleteANote(_id);
        if (!note)
            return res
                .status(HttpStatus.NOT_FOUND)
                .json({ status: 404, error: "Not found!" });
        return res.status(HttpStatus.OK).json({
            status: 200,
            message: 'Successful!',
        })
    }

}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;@ApiTags&lt;/code&gt; is used to annotate the class and return it.&lt;/li&gt;
&lt;li&gt;to specify and return the response type, the &lt;code&gt;@ApiResponse&lt;/code&gt; property is used to annotate the methods.&lt;/li&gt;
&lt;li&gt;read more about &lt;code&gt;short-hand API response decorators&lt;/code&gt; for swagger on the official docs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Run:&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;npm run start:dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and you'll see the documented APIs at &lt;code&gt;localhost:3000/api&lt;/code&gt;&lt;/p&gt;




&lt;p&gt;That marks the end of these series...&lt;/p&gt;

&lt;p&gt;For the full code: &lt;a href="https://github.com/funmi5/nestjs-notes-todo" rel="noopener noreferrer"&gt;https://github.com/funmi5/nestjs-notes-todo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks for reading.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>node</category>
      <category>typescript</category>
      <category>nestjs</category>
    </item>
    <item>
      <title>Get started with NestJS and create a todo "notes" app: creating e2e tests (Part 2)</title>
      <dc:creator>Funmi Olaiya</dc:creator>
      <pubDate>Sat, 09 May 2020 09:42:22 +0000</pubDate>
      <link>https://forem.com/feobaby/get-started-with-nestjs-and-create-a-todo-notes-app-creating-e2e-tests-part-2-5pl</link>
      <guid>https://forem.com/feobaby/get-started-with-nestjs-and-create-a-todo-notes-app-creating-e2e-tests-part-2-5pl</guid>
      <description>&lt;p&gt;Welcome back!&lt;/p&gt;




&lt;p&gt;If you read my last post:  &lt;a href="https://dev.to/funmi5/get-started-with-nestjs-and-create-a-todo-notes-app-4c67"&gt;https://dev.to/funmi5/get-started-with-nestjs-and-create-a-todo-notes-app-4c67&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wrote a comprehensive walkthrough on how to get started with using the NestJs framework, my general overview of it and why it should be considered for future projects.&lt;/p&gt;

&lt;p&gt;Now, we are back to the &lt;strong&gt;part 2&lt;/strong&gt; of the post which is about writing end-to-end tests.&lt;/p&gt;

&lt;p&gt;My &lt;strong&gt;understanding&lt;/strong&gt; of end-to-end testing and why it is important is that it helps to test an application's workflow from start to finish, it helps to test the endpoints by behaving the way a real user would.&lt;/p&gt;

&lt;p&gt;Why I totally love end-to-end testing is because it helps to prevent silly bugs and of course regression - &lt;em&gt;this works in a way that bugs make a feature stop working after on update/upgrade.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's get started:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the project created last time, check the &lt;strong&gt;tests&lt;/strong&gt; folder and you will see that a test had already been created for the entry &lt;strong&gt;GET&lt;/strong&gt; route upon creation -  &lt;code&gt;app.e2e-spec.ts&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP requests are simulated using the &lt;strong&gt;supertest library&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Then we initiate a request to the app that looks like that of a real HTTP request.&lt;/li&gt;
&lt;li&gt;Please, read more about the &lt;code&gt;INestApplication interface&lt;/code&gt;, the inbuilt NestJs &lt;code&gt;TestingModule&lt;/code&gt; and the flow of operation from the official docs on &lt;em&gt;automated testing&lt;/em&gt; here: - &lt;a href="https://docs.nestjs.com/fundamentals/testing" rel="noopener noreferrer"&gt;https://docs.nestjs.com/fundamentals/testing&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Modify the e2e jest config to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;changing the regex from &lt;code&gt;e2e-spec.ts&lt;/code&gt; to &lt;code&gt;e2e.ts&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "moduleFileExtensions": [
    "js",
    "json",
    "ts"
  ],
  "rootDir": ".",
  "testEnvironment": "node",
  "testRegex": ".e2e.ts$",
  "transform": {
    "^.+\\.(t|j)s$": "ts-jest"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a file called &lt;strong&gt;note.e2e.ts&lt;/strong&gt; in your &lt;strong&gt;tests&lt;/strong&gt; folder.&lt;/p&gt;

&lt;p&gt;Add the 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;import { Test, TestingModule } from "@nestjs/testing";
import { INestApplication, HttpStatus } from "@nestjs/common";
import * as request from "supertest";
import { AppModule } from "../src/app.module";
import { CreateNoteDTO } from "../src/dtos/note.dto";
import * as mongoose from "mongoose";

describe("E2E Tests for NOTE Endpoints", () =&amp;gt; {
    let app: INestApplication;

    beforeEach(async () =&amp;gt; {
        jest.setTimeout(10000);
        const moduleFixture: TestingModule = await Test.createTestingModule({
            imports: [AppModule],
        }).compile();

        app = moduleFixture.createNestApplication();
        await app.init();
    });

    afterAll(async done =&amp;gt; {
        await mongoose.disconnect(done);
    });

    it("should create a note", () =&amp;gt; {
        const note: CreateNoteDTO = {
            name: "My Travel Plans for 2020",
            description: "Plans to travel to Kenya",
            tags: "Travel",
        };
        return request(app.getHttpServer())
            .post("/note/add")
            .set("Accept", "application/json")
            .send(note)
            .expect(HttpStatus.CREATED);
    });
    it("should update a note", () =&amp;gt; {
        const note: CreateNoteDTO = {
            name: "My Travel Plans for 2020",
            description: "Plans to travel to Kenya",
            tags: "Work",
        };
        return request(app.getHttpServer())
            .patch("/note/update/5ead5c1a43ace404e06a7408")
            .set("Accept", "application/json")
            .send(note)
            .expect(HttpStatus.OK);
    });
    it("should get all notes", () =&amp;gt; {
        return request(app.getHttpServer())
            .get("/note/all")
            .set("Accept", "application/json")
            .expect(HttpStatus.OK);
    });
    it("should get a note", () =&amp;gt; {
        return request(app.getHttpServer())
            .get("/note/5ead5c1a43ace404e06a7408")
            .set("Accept", "application/json")
            .expect(HttpStatus.OK);
    });
    it("should delete a note", () =&amp;gt; {
        return request(app.getHttpServer())
            .delete("/note/delete/5ead5c1a43ace404e06a7408")
            .set("Accept", "application/json")
            .expect(HttpStatus.OK);
    });
});

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

&lt;/div&gt;



&lt;p&gt;And there you have it. We have successfully created e2e tests for the endpoints!&lt;/p&gt;

&lt;p&gt;For part 1: &lt;a href="https://dev.to/funmi5/get-started-with-nestjs-and-create-a-todo-notes-app-4c67"&gt;https://dev.to/funmi5/get-started-with-nestjs-and-create-a-todo-notes-app-4c67&lt;/a&gt;&lt;br&gt;
For part 3: &lt;a href="https://dev.to/funmi5/get-started-with-nestjs-and-create-a-todo-notes-app-documenting-the-api-endpoints-with-nestjs-swagger-part-3-67"&gt;https://dev.to/funmi5/get-started-with-nestjs-and-create-a-todo-notes-app-documenting-the-api-endpoints-with-nestjs-swagger-part-3-67&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For the code: &lt;a href="https://github.com/funmi5/nestjs-notes-todo" rel="noopener noreferrer"&gt;https://github.com/funmi5/nestjs-notes-todo&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>node</category>
      <category>typescript</category>
      <category>nestjs</category>
    </item>
    <item>
      <title>Get started with NestJS and create a todo "notes" app.</title>
      <dc:creator>Funmi Olaiya</dc:creator>
      <pubDate>Sat, 02 May 2020 15:54:53 +0000</pubDate>
      <link>https://forem.com/feobaby/get-started-with-nestjs-and-create-a-todo-notes-app-4c67</link>
      <guid>https://forem.com/feobaby/get-started-with-nestjs-and-create-a-todo-notes-app-4c67</guid>
      <description>&lt;p&gt;Recently, I took part in a challenge to work on a mini NestJS app and I fell in love with the framework.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The architecture?&lt;/li&gt;
&lt;li&gt;Easy to set-up CLI?&lt;/li&gt;
&lt;li&gt;or the fact that it fully supports the use of typescript?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The three points mentioned above made the experience wonderful and I'll be using NestJs for my future projects.&lt;/p&gt;

&lt;p&gt;According to the official docs, it is deemed a progressive Node.js framework for building efficient, reliable and scalable server-side applications. &lt;br&gt;
Check out the docs: &lt;a href="https://docs.nestjs.com/" rel="noopener noreferrer"&gt;https://docs.nestjs.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I use NodeJS and the express framework for back-end web development. Express is known and good for setting up quick, reliable and fast APIs but it does not enforce any architecture or solid principles of OOP, and this is exactly where Nestjs comes in.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Few interesting facts I got from using NestJs:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It enforces an architecture that ensures the developed/developing app is modular.&lt;/li&gt;
&lt;li&gt;It is very easy to document APIs using &lt;code&gt;nestJs/swagger&lt;/code&gt;, as it can easily be incorporated when the API routes are being designed.&lt;/li&gt;
&lt;li&gt;It contains all the features you need at the beginning of the project - this happens when you create a new app with the CLI.&lt;/li&gt;
&lt;li&gt;It helps to consistently demand the best logic and practice when developing new APIs - the reason being that you can not easily do a manipulation.&lt;/li&gt;
&lt;li&gt;It fits so perfectly with the use of the mongoose ODM and typescript - it helps the more if you are experienced in using mongoose with express.&lt;/li&gt;
&lt;li&gt;Who is happy with me? Yes, we can finally do away with babel.&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;A quick overview of how our app architecture will be structured:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa9ksgx6h1tgqild1xr6k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa9ksgx6h1tgqild1xr6k.png" alt="Alt Text" width="559" height="322"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Let us get started with creating to understand better.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Install nestjs and create an app using the following commands:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm i -g @nestjs/CLI&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After the installation is successful run,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then create a new nest project,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nest new project-name&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Since we are going to be using mongoose with NestJs, we have to install some packages.&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 mongoose -S
npm install @nestjs/mongoose -S
npm install dotenv -S
npm install @types/dotenv -S
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Create a database connection using the atlas mongodb connection string.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I am assuming you can set up a new cluster on mongodb called &lt;code&gt;notes-todo&lt;/code&gt;.&lt;br&gt;
If you have set up the database and gotten the connection string, good!&lt;/p&gt;

&lt;p&gt;In your src folder, create folders called schemas, interfaces, dtos, services and controllers.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Creating a schema.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A schema will determine how the data should be stored in the database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create a file in the schemas folder called &lt;code&gt;note.schema.ts&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Add the 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;import * as mongoose from "mongoose";
const { Schema } = mongoose;

export const NoteSchema = new Schema({
    name: String,
    description: String,
    tags: {
        type: String,
        enum: ["Personal", "Travel", "Life", "Work"],
    },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Create a file in the interfaces folder called &lt;code&gt;note.interface.ts&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An interface defines the kind of values(type-checking) the application must adhere to/receive.&lt;/li&gt;
&lt;li&gt;The readonly keyword depicts that the values can be accessed outside of the class but cannot be modified.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add the 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;import { Document } from "mongoose";

export interface Note extends Document {
    readonly name: string;
    readonly description: string;
    readonly tags: string;
    readonly createdAt: Date;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Create a file in the dtos folder called &lt;code&gt;note.dto.ts&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A DTO(data transfer object) depicts what the expected request should look like.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add the 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;export class CreateNoteDTO {
    name: string;
    description: string;
    tags: string;
    createdAt: Date;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Create the service provider class and methods for all the routes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the services folder, create a file named &lt;code&gt;note.service.ts&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add the 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;import { Injectable } from "@nestjs/common";
import { Model } from "mongoose";
import { InjectModel } from "@nestjs/mongoose";
import { Note } from "../interfaces/note.interface";
import { CreateNoteDTO } from "../dtos/note.dto";

@Injectable()
export class NoteService {
    constructor(@InjectModel("Note") private readonly noteModel: Model&amp;lt;Note&amp;gt;) { }
    async createANote(createNoteDTO: CreateNoteDTO): Promise&amp;lt;Note&amp;gt; {
        const newNote = await this.noteModel(createNoteDTO);
        return newNote.save();
    }

    async getAllNotes(): Promise&amp;lt;Note[]&amp;gt; {
        const notes = await this.noteModel.find().exec();
        return notes;
    }

    async getANote(noteId): Promise&amp;lt;Note&amp;gt; {
        const note = await this.noteModel.findById(noteId).exec();
        return note;
    }

    async updateANote(_id, createNoteDTO: CreateNoteDTO): Promise&amp;lt;Note&amp;gt; {
        const note = await this.noteModel.findByIdAndUpdate(_id, createNoteDTO, { new: true });
        return note;
    }

    async deleteANote(_id): Promise&amp;lt;any&amp;gt; {
        const note = await this.noteModel.findByIdAndRemove(_id);
        return note;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;@Injectable is a decorator that allows classes to be made available and be a provider.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;NoteService&lt;/code&gt; function is created and the note interface is injected through the class constructor using the decorator &lt;code&gt;@InjectModel&lt;/code&gt; from nestjs/mongoose.&lt;/li&gt;
&lt;li&gt;The NoteService class takes in five methods to help design the API routes.&lt;/li&gt;
&lt;li&gt;The main use of these methods is to abstract the logic away.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Creating the controller class and methods for all the routes:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the controllers folder, create a file named &lt;code&gt;note.controller.ts&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Add the 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;import { Controller, Res, HttpStatus, Post, Get, Param, Body, Patch, Delete } from "@nestjs/common";
import { NoteService } from "../services/note.service";
import { CreateNoteDTO } from "../dtos/note.dto";

@Controller('note')
export class NoteController {
    constructor(private noteService: NoteService) { }

    @Post('/add')
    async createANote(@Res() res, @Body() createNoteDTO: CreateNoteDTO) {
        const note = await this.noteService.createANote(createNoteDTO);
        return res.status(HttpStatus.CREATED).json({
            status: 201,
            message: "Successful!",
            data: note
        })
    }

    @Get('/all')
    async getAllNotes(@Res() res) {
        const notes = await this.noteService.getAllNotes();
        return res.status(HttpStatus.OK).json({
            status: 200,
            data: notes
        })
    }

    @Get("/:noteId")
    async getANote(@Res() res, @Param("noteId") _id: string) {
        const note = await this.noteService.getANote(_id);
        if (!note)
            return res
                .status(HttpStatus.NOT_FOUND)
                .json({ status: 404, error: "Not found!" });
        return res.status(HttpStatus.OK).json({ status: 200, data: note });
    }

    @Patch('/update/:noteId')
    async updateCustomer(@Res() res, @Body() createNoteDTO: CreateNoteDTO, @Param("noteId") _id: string) {
        const note = await this.noteService.updateANote(_id, createNoteDTO);
        if (!note)
            return res
                .status(HttpStatus.NOT_FOUND)
                .json({ status: 404, error: "Not found!" });
        return res.status(HttpStatus.OK).json({
            status: 200,
            message: 'Successful!',
            note
        });
    }

    @Delete('/delete/:noteId')
    async deleteCustomer(@Res() res, @Param('noteId') _id) {
        const note = await this.noteService.deleteANote(_id);
        if (!note)
            return res
                .status(HttpStatus.NOT_FOUND)
                .json({ status: 404, error: "Not found!" });
        return res.status(HttpStatus.OK).json({
            status: 200,
            message: 'Successful!',
        })
    }

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

&lt;/div&gt;



&lt;p&gt;Note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A class called &lt;code&gt;NoteController&lt;/code&gt; is created and the provider - &lt;code&gt;NoteService&lt;/code&gt; is injected through the class constructor.&lt;/li&gt;
&lt;li&gt;The five methods created within the class controller are only created to handle the incoming requests. Remember that all the logic have been abstracted away with the providers.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Create a feature module for the provider and the controller:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The purpose of a feature module is to simply organize code and establish boundaries and this principle makes more sense if the application is bound to keep growing, it is used with the &lt;code&gt;@Module&lt;/code&gt; decorator.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the modules folder, create a file named note.module.ts&lt;/p&gt;

&lt;p&gt;Add the 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;import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { NoteController } from "../controllers/note.controller";
import { NoteService } from "../services/note.service";
import { NoteSchema } from "../schemas/note.schema";

@Module({
    imports: [
        MongooseModule.forFeature([{ name: 'Note', schema: NoteSchema }])
    ],
    controllers: [NoteController],
    providers: [NoteService]
})
export class NoteModule { }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;The root module needs to be modified:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The module is the start point of the application graph and it encapsulates providers by default, but since we already have a defined feature module, all we need to do is import that &lt;code&gt;feature module&lt;/code&gt; and schema into this root module.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;app.module.ts&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Modify it by adding the 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;import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MongooseModule } from '@nestjs/mongoose';
import { NoteModule } from './modules/note.module';
import "dotenv/config";

@Module({
  imports: [
    MongooseModule.forRoot(process.env.DATABASE_URI,
      {
        useNewUrlParser: true,
        useUnifiedTopology: true,
        useCreateIndex: true,
        useFindAndModify: false
      }),
    NoteModule
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule { }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Finally:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In order to add an API version, we are going to use nestjs &lt;code&gt;setGlobalPrefix&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;main.ts&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Modify it by adding the 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;import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.setGlobalPrefix("api/v1");
  await app.listen(3000);
}
bootstrap();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Add the connection string to your .env file&lt;/p&gt;

&lt;p&gt;&lt;code&gt;example: DATABASE_URI = mongodb+srv://&amp;lt;username&amp;gt;:&amp;lt;pasword&amp;gt;@cluster0-xydxj.mongodb.net/notes_db&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;npm run start:dev&lt;/code&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;These API routes should be able to function:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;localhost:3000/api/v1/notes/add&lt;br&gt;
localhost:3000/api/v1/notes/all&lt;br&gt;
localhost:3000/api/v1/notes/:noteId&lt;br&gt;
localhost:3000/api/v1/notes/update/:noteId&lt;br&gt;
localhost:3000/api/v1/notes/delete/:noteId&lt;/p&gt;

&lt;p&gt;KeyNote: Read up more on Dependencies, Decorators, Modules, Providers and Controllers on the official docs: docs.nestjs.com&lt;/p&gt;

&lt;p&gt;For part 2: &lt;a href="https://dev.to/funmi5/get-started-with-nestjs-and-create-a-todo-notes-app-creating-e2e-tests-part-2-5pl"&gt;https://dev.to/funmi5/get-started-with-nestjs-and-create-a-todo-notes-app-creating-e2e-tests-part-2-5pl&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For part 3: &lt;a href="https://dev.to/funmi5/get-started-with-nestjs-and-create-a-todo-notes-app-documenting-the-api-endpoints-with-nestjs-swagger-part-3-67"&gt;https://dev.to/funmi5/get-started-with-nestjs-and-create-a-todo-notes-app-documenting-the-api-endpoints-with-nestjs-swagger-part-3-67&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the code - &lt;a href="https://github.com/funmi5/nestjs-notes-todo" rel="noopener noreferrer"&gt;https://github.com/funmi5/nestjs-notes-todo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nestjs</category>
      <category>typescript</category>
      <category>node</category>
    </item>
    <item>
      <title>Mini contact cards - using Algolia as the search service and setting the web app up as a PWA</title>
      <dc:creator>Funmi Olaiya</dc:creator>
      <pubDate>Wed, 19 Feb 2020 21:50:43 +0000</pubDate>
      <link>https://forem.com/feobaby/mini-contact-cards-using-algolia-as-the-search-service-and-setting-the-web-app-up-as-a-pwa-3fan</link>
      <guid>https://forem.com/feobaby/mini-contact-cards-using-algolia-as-the-search-service-and-setting-the-web-app-up-as-a-pwa-3fan</guid>
      <description>&lt;p&gt;Hello everyone,&lt;/p&gt;

&lt;p&gt;This tutorial will be about getting few details from a JSON object as mini contact cards using the front-end technology(react) and a search engine(algolia). The app will be hosted on netlify.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A quick note:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Algolia is a powerful search-service because the set up is quite easy, powerful, produces excellent search results and allows users to have a wonderful search experience. &lt;/p&gt;




&lt;h3&gt;
  
  
  Let's get started:
&lt;/h3&gt;

&lt;p&gt;-Make sure Node.js installed on your computer&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up react using this command - &lt;code&gt;npx create-react-app .&lt;/code&gt; &lt;em&gt;not&lt;/em&gt; &lt;code&gt;npx create-react-app my-app&lt;/code&gt; because the later command will install a folder into the folder you already specified and we want the folder structure to look like this:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frhmah88h8ilvfaodbl8h.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frhmah88h8ilvfaodbl8h.PNG" alt="Alt Text" width="308" height="160"&gt;&lt;/a&gt;&lt;br&gt;
Read more:- &lt;code&gt;https://create-react-app.dev/docs/getting-started/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;em&gt;App.js&lt;/em&gt; file, refactor the code to the 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;import React, { Component} from 'react';
import './App.css';

class App extends Component {

    render(){
    return (
      &amp;lt;div className="App"&amp;gt;
          &amp;lt;p&amp;gt;Random contact card&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
    );
    }
  }

  export default App;

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

&lt;/div&gt;



&lt;p&gt;We only need to render the title of the app for now. &lt;/p&gt;

&lt;p&gt;Add this to the &lt;em&gt;App.css&lt;/em&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;p {
    font-size: 50px;
    color: rgb(164, 193, 188);
    text-align: center
  }

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

&lt;/div&gt;



&lt;p&gt;In the &lt;em&gt;index.css&lt;/em&gt; file, refactor the code to the 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;body {
  margin: 0;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

&lt;/div&gt;



&lt;p&gt;An account needs to be created on algolia and once that is created, you will be redirected to a dashboard.&lt;/p&gt;

&lt;p&gt;Create an index titled -, &lt;em&gt;for example: search-details.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Under &lt;em&gt;add records to search&lt;/em&gt;, there are three options, &lt;code&gt;add records manually&lt;/code&gt;, &lt;code&gt;use the API&lt;/code&gt; or &lt;code&gt;upload file&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;We will be &lt;code&gt;uploading the records manually&lt;/code&gt; since they are just ten users we are trying to search for.&lt;/p&gt;

&lt;p&gt;Paste this JSON URL in your browser to get the full data: &lt;code&gt;http://jsonplaceholder.typicode.com/users&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After the full data have been copied, paste it to the algolia console and click save.&lt;/p&gt;

&lt;p&gt;Click on &lt;em&gt;searchable attributes&lt;/em&gt; and add the attributes to be used in searching. &lt;br&gt;
Tip: you can add name and email since that is what will only be searched for.&lt;br&gt;
Review and save settings.&lt;/p&gt;

&lt;p&gt;Create a folder called components and create another folder called &lt;em&gt;search&lt;/em&gt;, in it, create two files called - &lt;code&gt;search.component.jsx&lt;/code&gt; and &lt;code&gt;search.style.css&lt;/code&gt; in the search folder.&lt;/p&gt;

&lt;p&gt;Install these packages:&lt;br&gt;
 &lt;code&gt;npm install aloglia search react-instantsearch-dom -S&lt;/code&gt; - to integrate the Javascript API client and for helping to search the react-dom.&lt;/p&gt;

&lt;p&gt;Add this following code to the search.component.jsx file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import algoliasearch from 'algoliasearch/lite';
import { InstantSearch, SearchBox} from 'react-instantsearch-dom';
import {Content} from '../content/content.component';
import './search.style.css';

const searchClient = algoliasearch(
  '_APP ID_',
  '_Search-Only API Key_'
);
export const Search = () =&amp;gt; (
  &amp;lt;InstantSearch searchClient={searchClient} indexName="search-details"&amp;gt;
         &amp;lt;SearchBox 
            className='search' 
            /&amp;gt;
     &amp;lt;Content 
     /&amp;gt;    
  &amp;lt;/InstantSearch&amp;gt;
);

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

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;algolisearch app id&lt;/code&gt; and &lt;code&gt;key&lt;/code&gt; are assigned to a constant whereby a function is declared to use the &lt;code&gt;instantsearch&lt;/code&gt; component, retrieve the &lt;code&gt;searchClient&lt;/code&gt; and index of the records. &lt;br&gt;
The &lt;code&gt;searchBox&lt;/code&gt; is a widget used to let the user perform a text-based query - will be used for searching through the records.&lt;/p&gt;

&lt;p&gt;Add this code to the search.style.css:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input[type='search'] {
    justify-content: center;
    padding: 10px 30px;
    width: 40%;
    border: 1px solid black;
    margin-left: 30%;
  }

button.ais-SearchBox-submit {
      display: none;
  }

button.ais-SearchBox-reset{
  display: none;
}  

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

&lt;/div&gt;






&lt;p&gt;Back to the components folder:&lt;/p&gt;

&lt;p&gt;Create a folder called &lt;em&gt;content&lt;/em&gt;, in it, create two files called: &lt;code&gt;content.component.jsx&lt;/code&gt; and &lt;code&gt;content.style.css&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Add the following code to the content.component.jsx file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { Hits } from 'react-instantsearch-dom';
import { Hit } from '../hit/hit.component';
import './content.style.css';

export const Content =() =&amp;gt; (
&amp;lt;div className = 'content'&amp;gt;
    &amp;lt;Hits hitComponent={Hit} /&amp;gt;
    &amp;lt;/div&amp;gt;
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code merely houses the imported &lt;em&gt;hit&lt;/em&gt; component.&lt;/p&gt;

&lt;p&gt;Add this code to the content.style.css file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ul {
  list-style-type: none;
  width: 60%;
  margin: 0 auto;
  margin-top: 5%;
  }

  li {
  margin: 1em 0;
  }  


  @media screen and (max-width: 600px) {
    ul {
      width: 70%;
      margin-left: 5%;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Back to the components folder:&lt;br&gt;
Create a folder called &lt;em&gt;hit&lt;/em&gt;, in it, create two files called: &lt;code&gt;hit.component.jsx&lt;/code&gt; and &lt;code&gt;hit.style.css&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Add the following code to the hit.component.jsx file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import './hit.style.css';

export const Hit = ({ hit }) =&amp;gt; (
    &amp;lt;div className="hit"&amp;gt;
        &amp;lt;div className="title"&amp;gt;{hit.name}&amp;lt;/div&amp;gt;
        &amp;lt;div className="details"&amp;gt;Email: {hit.email}&amp;lt;/div&amp;gt;
       &amp;lt;div className="details"&amp;gt;Website: {hit.website}&amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;

);

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

&lt;/div&gt;






&lt;p&gt;In this code - &lt;code&gt;hits&lt;/code&gt; is used to display the name and email results that will be searched for. &lt;/p&gt;

&lt;p&gt;Add the following code to the &lt;code&gt;hit.style.css file&lt;/code&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 url('https://fonts.googleapis.com/css?family=Quicksand&amp;amp;display=swap');

body{
    font-family: 'Quicksand', sans-serif;
    width: 100%;
    margin: 0;
}

.hit {
    background-color: rgb(216, 229, 227);
    border-radius: 5px;
}

  .title {
    color: grey;
    font-size: 20px;
    line-height: 3;
    text-align: center;
  }

  .details {
      color: grey;
      font-size: 10px;
      text-align: center;
  }

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

&lt;/div&gt;



&lt;p&gt;The App.js file should be updated using this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { Component} from 'react';
import './App.css';
import {Search} from './../src/components/search/search.component';

class App extends Component {

    render(){
    return (
      &amp;lt;div className="App"&amp;gt;
          &amp;lt;p&amp;gt;Random contact card&amp;lt;/p&amp;gt;
          &amp;lt;Search /&amp;gt;
    &amp;lt;/div&amp;gt;
    );
    }
  }


  export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The search component is imported and rendered. &lt;/p&gt;

&lt;p&gt;Read more about the components- &lt;a href="https://www.algolia.com/doc/api-reference/widgets/instantsearch/react/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Now it's time to set it up as a PWA:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the Public folder, in the &lt;em&gt;manifest.json&lt;/em&gt; file, change the short name and name to &lt;code&gt;random-contact-card&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Create a &lt;em&gt;worker.js&lt;/em&gt; file in the public folder and add this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const CACHE_NAME = 'random-contact-card-cache';
const urlsToCache = ['/'];

// Install a service worker
self.addEventListener('install', event =&amp;gt; {
  // Perform install steps
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache =&amp;gt; cache.addAll(urlsToCache))
  );
});

// Cache and return requests
self.addEventListener('fetch', event =&amp;gt; {
  event.respondWith(
    caches.match(event.request).then(response =&amp;gt; {
      // Cache hit - return response
      if (response) {
        return response;
      }
      return fetch(event.request);
    })
  );
});

// Update a service worker
self.addEventListener('activate', event =&amp;gt; {
  const cacheWhitelist = ['random-contact-card-cache'];
  event.waitUntil(
    caches.keys().then(cacheNames =&amp;gt;
      Promise.all(
        cacheNames.map(cacheName =&amp;gt; {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      )
    )
  );
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the index.html file in the public folder:&lt;/p&gt;

&lt;p&gt;Add the &lt;code&gt;javascript&lt;/code&gt; code to the body to check if the browser supports service workers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
      if ('serviceWorker' in navigator) {
        window.addEventListener('load', function () {
          navigator.serviceWorker.register('worker.js').then(function (registration) {
            console.log('Worker registration successful', registration.scope);
          }, function (err) {
            console.log('Worker registration failed', err);
          }).catch(function (err) {
            console.log(err);
          });
        });
      } else {
        console.log('Service Worker is not supported by browser.');
      }
    &amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Add this code to the head of the index.html:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;link rel="manifest" href="%PUBLIC_URL%/manifest.json" /&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;&amp;lt;link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"&amp;gt;&lt;/code&gt; - the react logo is used for this app.&lt;/p&gt;

&lt;p&gt;Now, update the &lt;em&gt;index.js&lt;/em&gt; from &lt;code&gt;serviceWorker.unregister()&lt;/code&gt; to &lt;code&gt;serviceWorker.register()&lt;/code&gt;&lt;/p&gt;




&lt;p&gt;It is all set up. yay.&lt;/p&gt;

&lt;p&gt;It is time to run an audit on how far we have gone.&lt;/p&gt;

&lt;p&gt;Go to your browser console(I assume your project is running on the localhost already). Click on &lt;em&gt;audits&lt;/em&gt;, then &lt;em&gt;generate a report&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If it is giving an error, relax, it happens when it is the first time.&lt;/p&gt;




&lt;p&gt;Let us host it on netlify, which is the simplest ever.&lt;/p&gt;

&lt;p&gt;Firstly, push your code to GitHub, then&lt;br&gt;
Create an account on netlify -&amp;gt; sign in/up with git -&amp;gt; choose the project you wish to deploy -&amp;gt; the command should be &lt;em&gt;npm run build&lt;/em&gt; and the directory should be &lt;em&gt;build/&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When the project is live, try to &lt;em&gt;generate report&lt;/em&gt; again. &lt;em&gt;it is best to be done in incognito mode&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;See it in action - &lt;a href="https://codesandbox.io/s/random-contact-card-qchni" rel="noopener noreferrer"&gt;codesandbox&lt;/a&gt; &lt;br&gt;
For the code - &lt;a href="https://github.com/funmi5/random-contact-card" rel="noopener noreferrer"&gt;github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks, for reading!&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>algolia</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
