0% found this document useful (0 votes)
14 views29 pages

Class 3 (NestJS) (EN)

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
14 views29 pages

Class 3 (NestJS) (EN)

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 29

Web app development

M1 S1 2024 - Gérald Gallet


API REST

A REST API, unlike a web page, will send raw data in the JSON format. It is made of routes, and uses HTTP
verbs (/methods) to process different actions.

- GET get some data


- POST create new data
- PUT replace data
- PATCH update
- DELETE delete

Other methods exist, that we won’t use ourselves, that are here to help the browser manage requests

- HEAD like GET, but only with the headers


- CONNECT establishes a connection
- OPTIONS get communication options
TRACE test message to follow the request’s path

2
API REST

To send our different requests, we will use Postman (https://www.postman.com/downloads/). It allows us


to send requests to our server to test it.

- Server URL

- HTTP method

- Server response

3
API REST

A request will sometimes send data (a response body), and always an HTTP code. Codes go between 100
and 527. Each hundred corresponds to a kind of result
1xx information (ex. processing)
2xx everything went right
3xx request is redirect
4xx user error
5xx server error

Exemples:
200 OK
204 Created
401 Unauthorized
403 Forbidden
404 Not found
418 I’m a teapot
500 Internal server error

4
NestJS

The NestJS, inspired by Angular will allow us to build an API using a modular architecture.

It is based on the express library that allows us to transform our server NodeJS into an HTTP server ready
to receive and respond to requests.

The modular architecture promotes the responsibility separation. Each kind of class has a precise function
and is splitted into its own file. Then, for each functional notion, we create a module that builds every layer
of this feature.

The first 3 notions we will find are those ones :


- Controller defines routes and handles input / output
- Service handles feature rules and specific calculations
- Repository handles the storing logic, communicating with a database

5
NestJS

Preparation:
- Download the m1-api folder
- Run command npm install to install dependencies
- Run command npm run start:dev
- While you’re at it, you can install the dbaeumer.vscode-eslint VSCode plugin that will help us on
code style (we will come back to that later)
The console would look like this.

6
NestJS

Unlike before, we are running a server that won’t stop until a crash happens, or until we manually stop it
with CTRL + C.

We are running the server in “watch mode”: as soon as we save our changes, the server reloads with the
updates.

npm run start:dev allows us to run a script defined in the package (npm run), the name of the script is
start:dev.

7
NestJS

We go back to Postman, where we create a request calling the root of our API, on the port 3001. The port
3001 is defined (in the main.ts file) by an environment variable, which are defined in the .env file. This file,
coupled with the dotenv package, allows us to define environment variables existing only in our application
at runtime.

8
NestJS

NestJS works with modules that encapsulate our features.

A module defined multiple things with the @Module() decorator.

- imported modules
- defined controllers
- defined providers (we will come back to that)

Modules are all centralized in the AppModule, that is used to start the server.

They are defined in a <x>.module.ts, and each have their own folder.

You can find the first module in the app.module.ts file (CMD/Win + P in VSCode to search a file by name).

All of our code will always be in the src folder.

9
NestJS

Controllers are by convention defined in a <x>.controller.ts file. They export a class whose name ends with
Controller.

The @Controller() decorator lets NestJS know that this class is used to define routes.

I can give it a string as an argument to define a prefix for all my routes.

The @Get() decorator above a function allows me to define a route whose method is GET.

I can give it an argument to add a prefix to my route, or to get variables from the URL.

10
NestJS

For now, we have a controller with no prefix, and a GET route with no prefix, so we can only call
localhost:3001/ (localhost is the local server, your computer)

11
NestJS

For a REST API, convention is that if I touch a resource, books for instance, routes are prefixed by the
pluralized name of the resource, here, /books.

Then, classic operations are :

- GET /books get a list of books


- GET /books/:id get one book by its ID
- POST /books create a book
- PATCH /books/:id update a book
- DELETE /books/:id delete a book

This is what we call a (L)CRUD: (List), Create, Read, Update, Delete.

A full CRUD allows me to fully manage a resource.

12
NestJS

A variable contained in an URL, represented by :<nom de la variable> is called a parameter. I can get it in
NestJS with the @Param() decorator.

13
NestJS

Exercices
1. Create a new route GET /:id in the AppController that sends back the given ID
2. Create a new controller BookController, declare it in AppModule and implement following routes :
a. GET /books get a list of books
b. GET /books/:id get one book by its ID
c. POST /books create a book
d. PATCH /books/:id update a book
e. DELETE /books/:id delete a book
f. Just return the name of the function on each route to test if they work

All decorators are imported from the @nestjs/common library, you can do CMD / WIN + . so that VSCode
offers you to add the import to your file.

Once the routes created, test them on Postman to make sure they work

14
NestJS

As we said, NestJS has a modular architecture.

Before proceeding, we are going to create our book module and put our controller in it. We put this module
in a books folder, and we create another level before that with the modules folder.

15
NestJS

Then, we import our new module in the AppModule, so the application can be aware of it. For the import,
VSCode should automatically offer you the right path, don’t write it by hand. We check that the routes still
work with Postman.

16
NestJS

If I want to send data to the server, I first have to type my input using a DTO (Data Transfer Object)

A DTO allows me to receive a bigger payload than a string contained in the URL, while making sure of the
data type sent to me (never trust the external user)

I can create them in a .dto.ts file like this :

17
NestJS

To use it, the @Body() decorator of @nestjs/common allows me to get the payload in a POST request like
this

18
NestJS

On Postman, I send a body to a POST request like this:

19
NestJS

@IsString() allows me to check the field is a string, if I try to send a number, the server automatically replies
with a 400 (Bad Request) error.

20
NestJS

Many things are possible with validation, the most common are :

@IsString() field is a string


@IsNumber() field is a number
@IsInt() field is an integer
@IsDate() field is a date
@Max(x) field has a max value of x
@Min(x) field has a min value of x
@IsArray() field is an array
@IsOptional() the field can be undefined
@IsUUID() field is a UUID
@Type(() => OtherDto) field is an object defined by OtherDto

21
NestJS

Exercices
1. Create a DTO for authors with a first name and a last name
2. Create a DTO for book creation, with
a. a title field
b. a “publishedYear” field, that is an integer between 1500 and 2024
c. an author field corresponding to the previously created DTO
3. Create another DTO to update a book. I don’t have to update everything at the same time, so all
fields are optional.
4. Get those inputs in creation and update route, and log them or return them to make sure they are
received

22
NestJS

Now that everything is set, we can begin using services.

As said before, since the controller only handles input and output, the service will have to handle business
logic.

Let’s create a file book.service.ts, that declares a class BookService. The BookService will then be declared
in the BookModule, in the providers property.

23
NestJS

Our BookService, once all functions created, looks like this :

24
NestJS

The @Injectable() allows NestJS to know that this class can be injected into another.

Once declared in a module, NestJS will instantiate a single instance of our class, that we can use like this :

25
NestJS

Now, the problem we have is that we have DTOs in our service, but they are supposed to be only in the
controller layer. We don’t want that, because the user input might need transformation before being
processed by the service, and it’s the controller’s job to do that.

We are going to define a model file book.model.ts. We will define types just like our DTOs, and those types
will be used in our service.

For models, we usually end their names by Model to get a faster understanding of what they are:

26
NestJS

Exercices
1. Create the BookService and move controller functions so that they only call the service
2. Create BookModel, CreateBookModel and UpdateBookModel models.
a. For UpdateBookModel, use the CreateBookModel type and a native utility type from
TypeScript
3. Use those types in your service
4. In your BookService, add the following line.
5. Really implement all functions, using this array as a database
a. Watch out, this “DB” will be emptied everytime the app reloads

You can access it in the BookService using this.books.


When you create a book, add a randomly generated id with the v4 function of the uuid library.
27
NestJS

Now that our CRUD is working again, we still have one layer to see: the repository

The job of the repository is to abstract the storage layer of our application.

It is going to give the service the functions it needs to read / write data, while hiding the exact
implementation of those functions.

Whether our database is SQL, noSQL or something else, the service should not know.

The final goal is to split each layer this way is about code reusability.
If I switch from SQL to noSQL, I only change code in the repository.
If I switch from REST to GraphQL or SOAP, I only change code in the controller.

28
NestJS

Exercices
1. Create a BookRepository class in a book.repository.ts file.
2. Inject it into the BookService
a. Use the @Injectable() decorator
b. Declare the repository in the providers of our module
3. Fully move the “database” implementation in the BookRepository

29

You might also like