Transcripts
1. Introduction: Welcome to my course next, GS built-in real
application from scratch. It's so great to have you here. In this course, we will build a completely real application
from start to the end. And we will implement
all features of typical project such
as authentication, pagination, managing articles
like an in disliking them, following users and
much, much more. We will use nastiest together with typo room and Postgres, which is the most
popular solution to build scalable applications. Of course, all our
code will be dry, reducible and
digital understand. By the end of this course, you will for sure have
enough knowledge to build your own projects by using
mass Chess. Who am I? My name is Alexander, and I'm a web developer with more than ten years
of experience, as well as a professional
instructor with various courses regarding
different web technologies. I did my best to put
all my knowledge inside this course and they want
to share it with you. So welcome on board, and let's get started.
2. What technologies we will use?: In this video, I
want to talk about technologies that we
will use in this course. And of course, this course
is about Nest chairs. This is why it is
our main technology. And actually as you know, the most popular framework
for Node JS IIS Express, we can build, for example, any pie or a back-end for our web applications
by using Express. The main problem with Express
or similar frameworks, they are really low level, which means we need to implement a lot of
staff on our own, even like basic things that I'm waiting to have
in all frameworks. What we have from nest, yes, actually nastiest
reminds me a little bit, Ruby on Rails from Ruby world. And from my point of view, Ruby on Rails is one of the best examples of a well
made Framework. Why is that? Because we have a lot
of stuff out of the box from there and we don't
need to reinvent the wheel. For me, NES js inside node world is something
like Ruby on Rails, which means we have a lot
of stuff out of the box. For example, here
in documentation we have controllers,
providers, modules, middlewares, and a
lot of stuff that help us to build
real applications. So we don't need
to implement first the framework and done
within our application. The next important point is that nest years is written
with TypeScript directly, so we don't have
JavaScript there. Why this is important. Actually, JavaScript is really easy language
to start with, but it's not that save and stable because we don't
have datatypes there. And TypeScript eliminates
this problem like 90%. Maybe this is why I highly recommend you to use in
real project TypeScript. Why? Because in your project
you can describe with TypeScript all your
entities datatypes, and you are getting
a lot of warnings during compile state
and not in John time, which means
JavaScript is nice to build small and
medium applications. But for medium and
big applications, I highly recommend you
to look in TypeScript. But of course, the risk
pros and cons here. This means that to
master ness chess, you must learn TypeScript. And if you don't know
TypeScript for this course, no virus, I will cover some basics of
TypeScript also here. But you should be aware that
if you know TypeScript, then it will be easier for you to make this
course to the end. The next thing
that I'm expecting from framework is of course, connecting to databases and
work with them efficiently. And as you can see here, we have a section
database and NES GIS has a really nice wrappers and
rams to work with databases. Which means we can use
here different databases. We have different
providers for them. And this is quite simple. We don't need to build
something on our own. We just need to understand
how it all works together. But here is also
a small problem. We will use type or m here. And the REM means that this
is object relational mapper. So it is some wrapper
for our database. And type works with
different databases. But this is one more
layer that we need to understand and master in
order to work with Nest? Yes, because obviously
we need to work with databases and Dinesh just
we're doing it with Iran, which is completely correct. But it is additional
knowledge that you must know. If you had already some
experience with ramps, it will be easier for you
to complete this course. Also for our application, we'll, we'll use Postgres database. And if you don't
know, this is really popular open-source
relational database. So actually you must also know a database and
how they are working, at least on some level. We will start from scratch and I will show you everything
that you need, but you should not
expect that you will learn until the
end of the course, the whole Postgres
from start to the end. Because we're
focusing on building the application by using different technologies that you need for our real application. Also, here are two more
things that if you know, will make you easier to
complete this course. First of all, is Angular. If you ever worked with
Angular and you know how dependency injection
is working there, then it will be easier for you. If not, no worries, we will learn it
with nice chairs. But actually nastiest took a
lot of stuff from Angular. This is why it is
easier for you to master nice chairs if you
already know Angular. And last but not
least, of course, if you've worked with NodeJS
or you build, for example, express in Node.JS,
then it will be also easy for you to build
project with nudges. But you should not be worry. We will go through all
technologists from the start. Even if you don't know anything, this is completely fine. We will make it together.
3. What we will implement?: In this video, I
want to show you what we will implement
in this course. And actually here
I opened don't get hub golf things to real-world. What is the real-world? This is the real projects
that people are built-in in different languages
or frameworks in front-end and back-end side. And the main point
here is that it's not some HelloWorld or
to do MVC project. This is a real project with authentication registration,
working with feeds, working with APIs
like and dislike impulse following users
and much, much more. This is the serious
business here. The main idea is that
in this course we will implement the full
API for this project. So everything that you see here. And then we can take any
front-end that we want and just connected to our API and
do work out of the box. Here, as you can see, we have
a lot of implementations of front-end and of
course backends. Here I opened the really
important URL fast. Here we have real-world
API specification. This is exactly what
we must implement. For example, here you
can see all examples of all requests that we
must do in this course. For example, here, this is
how the response will look. One-world authenticate users. Here is profiles, single article, multiple
articles, and so on. Also, there are error codes for back-end validation and
of course endpoints. For example, to make a login, we must implement the endpoints slushy Pi slept
users slash login, where this will be the request and response you
already saw on the top. So actually this is our
main source of knowledge, but this is all requests that we will implement
in this course.
4. Generating a project: In this video, we will install mixtures tools and then
generate nice JS application. The first step here
is to install NodeJS. If you don't have known
just on your machine, you can always jump to known chess.org and download
here aversion. And actually there is
an important point. So first of all, we want to check what
version do we need? I am on the official
website and just.com, and here on the left
I chose first steps. And as you can see here, the important lines
your notes version must be higher than ten except of 13. And actually here,
as you can see, we have 14th version or 15th. Both versions will work, but I highly recommend you
to always use an OLTP, especially because
normally it's more stable. If you already have known, you can always check
in the console, node minus version must
return to some version. This version is higher than ten, then you are good to go. The next step is to install CLI. What did this, as
you can see here in the setup of the project
when style globally. Next GS CLI command line tool that help us to work with
nurse just for example, generate nurse JS project. Then later we can use nest knew and the
name of the project. This CLI tool will generate
our project files. So actually you can just copy, paste this command and paste
it here in the console. And they won't execute it
because I already did it previously and my nest
is already installed. So after installation
you want to check if nest is installed. This is y here. Nest minus version should
return you some version. If you are getting here,
some version doesn't really matter what version
you're good to go. Last but not least is of course, to generate our new project. As you can see for
this word, right? And nest knew and the
name of the project. I have Nest New. And let's name our
project medium clone, underscore goodness, Chess. Why medium clone? Because as I said in
the previous video, this is the clone of
the medium website. Now as you can see, we're getting several questions. First of all, what package
manager we want to use. It doesn't really matter, but I prefer normally to
use yarn and not NPM. Now as you can see, nest CLI installed all packages and generated fast project. This is why at the
end I'm getting successfully created
project and we can start it by writing CD in this folder
that was created, then yarn around stat. And if you chose
not yarn button PM, then here you will probably
see command npm start. This is why I am
jumping directly inside medium columnist Jess. And here I want to
start the server and they will do it in the
separate tab here. I want to jump to medium clone nest chairs
and dried yarn start. It actually doesn't matter
if you are right in the yarn around
style or yarn start, both will work the same. Now we're getting here, message nest application
was successful, is started. And actually the main problem is that there is no port here. So you need to check the documentation
or the source code. But they can say that
normally this application by default has been started
on 3 thousand port. Here I have localhost
3 thousand. And now when I am
reloading the page, you can see here Hello world. So actually this
is our web server and our generated
nest GIS project. Now let's have a look on our file structure that
was generated files. Here, I opened our editor
and as you can see, I'm unfolded medium
clone as chess. This is exactly
what was generated. What is important for us. First of all, of course, our source folder in Node modules we have
all dependencies. And in dist, all our
TypeScript is transpired. Because actually when
we're open source folder, you can see that this
is all tiers file, so we're right in
TypeScript here. And everything is
started here in main.js. As you can see, this
is what we have. We have here an asynchronous
function bootstrap. And here we're creating new nest factory where we're
bison inside a module. And actually this line
creates a new application. Then here we're saying that our application must
listen on 3 thousand port. Here we're calling
this function. This is why our application
is listening 3 thousand port. This is exactly what
is specified here. Our next step is In module. So let's jump to the module. This is this file. This is how our module
is looking like. And actually what is
module in next chess, if you already
familiar with clock, you can just apply
all knowledge about modules from Angular
two messages. If you don't know
anything about N color, then the way home USGS
is structured and applications is through
dependency injections. What does it mean? Let's say that we have several modules inside
our application. For example, module
of authentication, module of articles, and maybe at some other module,
maybe popular tags. And then we can say explicitly what is
inside this module. So we're defining. Dependencies of every module. For example, we can
create a service or controller inside each module, and then they are really
belonging to that module. And then we can say that our first module is dependent
on the second module. And then our first module can use something from
the second module. And if we don't provide
it as a dependency, then this is really
isolated stuff. So we will talk deeper
about modules later. For now, you just need to
understand that we need modules to oscillate
logic and split it. And in this case,
this is app module, which means this is the main
module in our application. And from wheat, everything
is started fast. Here is the most interesting
part is this controller. As you can see where
registered here, the dependencies
of our app module. This is this app controller and instead providers
App Service. Let's check what we have inside. As you can see, this
is app controller. This is how it looks like. We will talk also deeper about controllers
in the next video. For now, what is interesting for us is this get hello method. As you can see here,
we have a get and actually this is saying
that this has GET request. And here is our
get hello method. And now inside where column this App Service and
get hello method. Actually we can assume
we don't know yet that this gets yellow is what is rendering this Hello
World on the screen. Now let's check what we
have inside service. As you can see here, we have
this observers get hello. This is this App Service. Let's open now as serous. And as you can see, this is just a class where we
have get hello string, which returns as HelloWorld. We can already a
little bit understand how application of Nash
chairs is working. First of all, we
have our main tiers. Then inside main tiers were
registering our app module. And inside that module
we're registered, for example, app controller
and depth service. Now we have our controller
where we define some methods that will be called when we're jumping in
our case to slash, which actually means
this is the method for our default slash URL. And inside here we simply
return our get hello method, which returns as a string. This is why here
we have a string. And of course I understand
that you see here a lot of new staff
like constructors, read-only services,
controllers, and much more. We will talk about a
deeply in the next videos. But for now at least you saw what application
was generated faster. Then next super
important thing to mention is this dist folder. And actually dist folder is all the same files that we saw already like App Controller, app module App Service, Mencius. But it is in JavaScript, which means TypeScript
transpires on the fly. All these files here, and we're using them
inside our server. Now here are two more
things that you need to install in order to start
developing an application. First of all is support of
TypeScript inside your editor. As you can see here
when I'm champion, for example, in that module, I have here highlighting
and also stuff like outer important
autocomplete because I have test server
inside my editor. If you're using
some modern editor, for example, VS Code, which is really popular, you have that TypeScript
support out of the box. If you're using
some other editor, you can simply Google for
your editor some plug-in for TypeScript support
because it lists you want outer complete and
syntax highlighting. The last tool that
you need is Postman. What is Postman here? I open that tab, postman.com
slash downloads. And actually this is
how it looks like. This is a special
tool that we will use a lot in order to
make our request. For example, here
I can hit unclass. And now here I can write my
request, for example, http. And we'll know that we
have localhost 3 thousand. This is get here on the left. Now I can click Send, and as you can see here, I'm getting as a result, Hello World here on the bottom. This is exactly the tool to do all requests to specify here, headers, body, and so on. So by default, this tool
is completely free. You don't need to pay anything. You simply need to
jump to download Postman and don't load
here an application. But of course there
are the tears that actually you don't
need for that course. This is y here on the top
you have price and tab, but we will use here
on the free version, and this is completely
sufficient for our needs.
5. Creating tag module and controller: In this video, we will create our first module and controller. And they want to start
with something simple. And actually here
as you can see, I opened again our
API specification. Here is one endpoint
list of tags. As you can see, this
is how it looks like. So actually this
is the response as an object was filled Tags and inside we have energy of our possible tags
for our application. And as you can see inside, this is simply strings. And here is how it
looks like in front and here I opened
angular real-world IR. So this is one of the
front-ends for our API. And here on the right you
can see popular textblock, and these are all texts that
we have in this application. So actually what we need
to build is an entity tag. And then inside we will
store all our popular texts. But in this video
we will make it easier without database just by creating a new module for
our tag and you control it. So let's open our editor and now jump inside
source directory. As you can see here in source, we have everything flat. So we have here App Controller, app module, App
Service and Maine. But the point is that we will create a lot of different APIs, like an API for the user, authentication profiles,
tags, lists, and so on. Which actually means if we
will just throw all data here, it will be a mess. This is why the
good approach is to isolate everything
inside modules. So the idea is that we
have here at module, this is our main module. And then for example, for tags, we can
create new module. Then later we have
maybe articles. Then we create a new module
and isolate everything which is related to articles
inside that specific module. So let's create here a new
folder and call it Tag. So actually the name
convention, the toll-like, is to name all our
modules as singular. This is why it will be tagged or profile or user,
or maybe article. Now inside tag, Let's create
our tag dot module.js. As you can see,
we're always create a module file for
our new module. Here to the important part. The first one is the
name of our module. Then we have this
post fixed module. It is important in STS, we're naming all our
entities with postfix. In this case, we rarely
see what it is about. Now on the right, let's open our app module so
we can look how it works. As you can see here, our main
idea is to export a class. This is where here I will write expert class and here
will be tagged module. And again it's not
tag, it's tech module. So this postfix is important. Secondly, we're using here
a decorator module to specify some additional
configuration for our module. Here what we need to
do is write at module. Here. As you can see, I have
an auto-complete from Nest JS common because you really want this
outer complete. You don't want to type
every input on your own. In this case, I just typed module and then I
got auto imports. We will have lots of inputs. This is why we should
not write them by hand. Secondly, inside
module, as you can see, where must provide an object
with some properties. So now we successfully created
our first empty module. It doesn't do anything. And at this moment it's not binded inside our application. What we must do to
bind it is jump back in our app module
and import it here, because for now I will
take module is not registered inside
our application. We need to jump here in app module and
inside inputs array, right, our new tag module. And as you can see, I also
get an autocomplete here. Here are the important part. As you can see, we have
lots of stuff here. We have imports,
controllers and providers, and actually all dependencies of our module we're
writing inside inputs. This is why here we
have our app module, which is the main module. And here we define our
dependencies of app module, which actually
means if we want to buy a new modules
to our application, we'll also need always to register them here
inside the inputs. Now let's check that we
don't have any errors. So let's jump back
inside our yarn start, as you can see here is my web
server, and as you can see, no errors here, which means we're binded
everything successfully. We can also jump in browser and reload this local
host 3 thousand. And as you can see, our API
request is still there, which actually means that
everything is working. Now we must create a controller. So the question is
what is controlling? It is a place where we
define in all our APIs. Which actually means
if here we open our API structure and as you can see here is
the request and get tags slash api slash texts. So we want to create
this request. To do this, we need a controller because
this is the only place inside niches where we're
registering our URLs. So our API. In this case, I want
to jump back in our project and create
here in your file. And I will name it
tag controller.js. And again, tag is the name of the module controller is to our postfix and Ts
is an extension. Now what we want here, we want to create a class and the class will
be tag controller. The next step is to add
here decorator control it. And actually here in STS, we're writing a lot of
decorators because it's really sugary stuff to add some additional properties
or additional logic. In this case, I am outer
important controller from last year's common. And actually if we
don't try this line, then nothing will work because then it's not nest
chairs controller. In this case, we're registered that this is exactly
the controller. We created this file
and our first-class, but we also need to bind it to our module because for now
without binding ETL module, this file is not
visible for our app. For this, we need to
jump in our tech module. And here inside our module, we can create new property
which is called controllers. And here is the array of our controllers that
we can provide here. And denote case it will
be tagged controller. Once again, what
we are doing here, this thing is called
dependency injection. So we're injecting
dependencies and split all our
application in modules. And in this case we
define the tag module. And inside we have
some isolated stuff. In our case, the isolated
Staph is this tech controller. It's not visible
from the outside, but actually it will
be binded correctly when we're binding to our app
module, this tech module. It's also really
important that we can now remove completely
tech module for example. And then it is just gone
from our application because everything is related to tech
module is defined inside. Now it's time to create
our first route. So let's jump back
in our controller. And here we must
provide some functions. And actually when we're
creating here f function, then we will create
here a new route. And actually let's open
on the right here, our app controller tears. As you saw here, it looks a little bit similar
like we wrote. So we have here
controller and class. And here is get function. When we want for some
EPI to return some data, we must create here a function. As you can see here, we
have function get hello wherever we're rendering
this Hello World string. And different site tech
controller will want to return our list of tags
like you can see here. Then we must create here
additional function. And we can name this
function how we want. We can write here f2, but of course we want
something human-readable. And actually the
idea is the tower slash API slash tax
returns for us, the array of all possible tags. This is why here I
will name it, find o, which means actually
we will find all our texts here
and return them. Now inside we can simply
return whatever we want. For example, here let's say
that we have several texts, dragons and maybe coffee. This on our array of tags. Of course it is marked, but this is good for now. But the next point is that
we didn't register any API. As you can see here, we simply created a method
inside our class. So what is important
is to add here on the top of our
function decorator. And we can name it get, for example, as you can see, get decorator and don't
forget round brackets is a decorator which
creates a GET request, which actually means here
slash api slash tax is a GET. This is why here we are
right in and get the crater. Which actually means
creating a function without the decorator
doesn't do anything. This is why for every function that must work for our API, we must provide here
some decorated like get, post, delete,
whatever we need to. Now the question is, how do we provide a route? As you saw here inside
our app controller, would don't provide
here any route. This is why we can
see on our slash. So this is a default
homepage, this Hello World, which actually means if we
don't provide anything, then this get will be
our default homepage. And we don't need this
because we really want to implement slash tax. Actually here everywhere
you can see slushy pie. But as our project is on the isolated API
or you don't see any point to write
everywhere slash API. We will always write
the URL without the Pi. This is why we've wanted
to create slash tags. And for this, we need to know a controller to write
tags like this. What does it mean?
Actually, this means that we are registering
this whole controller. So all methods inside this
controller with prefix tags, which actually means that
now we can jump here in our local host 3 thousand
and tried slash tags. Now I'm hitting Enter,
and as you can see, we're getting status code
for 04 cannot get tags. So actually this is happening because we're using
wrong command. Actually, as you saw
in our web server, we used yarn start. Now let us look on
our package JSON. As you can see,
there are lots of commands that are
already prepared for us from Nest chest here or start command
that we're using. This is just nested
what it does. It simply transpires our
project and the toll. And actually all
our changes that we made are simply
not there because this command is not doing any
changes until we started. Actually start is
not the command that we want to use
for development. And as you can see here, we also have started dev, started debug and start broad. And as you can understand, broad is for production. Debug is for additional
verb balls messages, and dev is for development. So let's now start
with start depth. Then we have this
minus, minus voyage, and this is exactly
refreshing on our changes. This is why here we
want to write the yarn stored and here will be deaf. As you can see now, we have
command netstat minus minus. Here we can see starting
compilation in watch mode. And now actually
this information here is important because
as you can see here, we have started nest
application and here we have tech module
dependencies initialized. This actually means
that it was successful binded our tag module
because in other case, it won't be registered here. As you can see here, we can see all modules that we bind it. And as you can see here, we also have app controller. This is the default ones. Here we have tagged controller
and this is slash tags, which actually means
with this line that was successfully created our
first route slash tags. Also here on the bottom you
can see this maps line. So actually met. Then slash tags get this part
is exactly our function. This function, because here all functions that were
registered will be written. As you can see here. For example, for app controller, we have mapped here, we don't have any URL, so it is home, and
here is scared. So this is home URL and
this is slashed tags get. Now let's check if it's working. So let's jump in browser
and reload the page. And as you can see here, we have slash tags and we
returned our array of data. So actually we successfully
created our first module, tech module and our
first controller. We even created here
our first method, find all where we returned
the ray of plain data.
6. Creating tag service: In this video, I want
to talk about services. So actually we're
already know what our controllers for where
registered URLs there. And actually we can write the
whole logic, for example, connecting to database
and then fetch and some data from database
directly in controlling. But we can do better because
the point is if we have, for example, ten
methods that we want to register inside
our hotel controller. This means quite a lot of code. And actually we don't have
normal loop online are there. But we can have like ten or
20 lines inside each method, which actually means we will
create the super huge file. So the main idea is that for
these values and services, what this service,
this is simply some additional class
with some methods. And normally, for example, if we are talking about tags, we want to create tech
service where we will store all business
logic related to tag. And then inside controller
we simply use the service. So we don't have
any business logic inside our controllers. Of course in Nest just normally we're working a
lot with database, which actually means
all database requests were doing also
inside our service. In this case, we have
tech controller. Let's now create
our tech service. Here I will create tag, the service dot ts. And inside I will
create our first-class. Previously here we're right, an expert class, and here
will be our tech service. And again, we're postfix
in is with word service. We also need to register it as an injectable service for
our next JS application. Because in our case now
this is simply a class. This is not a service
which nest just nodes. This is why on the
top we want to write our decorator injectable. And as you can see here also round brackets are
important as always. Now, we want to move all our business logic from
our controller to service. This is why here I will
jump in tech controller. And as you can see, this
is our business logic. Sure, this is just
a single liner, but normally it
will be much more. What we want to do is we want
to create inset service, some method that will
return this data. This is y here
inside tech service. Or we can create new function
find all here inside. We simply can
return these lines, so return dragons and caution. Nothing special here, but this business logic is
inside our tech service. The next step is that
we must register our tech service
inside our module. Because in other case, we can't use it inside
our controller. This is why I will jump
in our tech module and here I will create one more property which
is called providers. And normally we're registered all our service
inside this property. This is why here I am
right in tech service. There is the tech services also isolated inside our module. Now we can use this service
inside our controller. Let's jump to our controller. And here on the top to
register our service, we need a constructor. So if we want to use some
service inside our controller, we must always define
it inside constructor. Here, inside
constructor we can say private and actually
even read-only. And here will be tech service. So this is our local property. And then I have
here take service. Here. We need to close
our constructor. So the idea is that here
inside constructor, we're defining all our
services that we want to use inside this
controller and denial case, we wrote here private read-only. So first of all, it's
not available outside. Secondly, it is read-only. And now we can use this text
service as local property. This is our local
property and here will be the instance
of our tech service. So now here, instead
of this return, we can write return and here
will be this text service, as you can see now we have
tech service inside this. Here when I am writing dot, you can see autocomplete
of TypeScript. This is our find all
methods that we wrote. And now we can remove
this one liner. Now we simply have the function called
from our tech service. Why it is good? First of all, we isolated full business logic
inside Service, which means we can separately test controllers and services. Our controllers doesn't know anything regarding
some business logic or database work because it
is isolated Insight Service. And also we can
share our services between different
modules if we want to. Let's check if it's working. I will jump inside Overwatch. And as you can see, actually
now we have a batch mode, so we don't need to
restart our web server. Now let's jump in browser
and reload this page. As you can see, it
looks exactly the same. So now let's check some strings
to see if it's working. I will jump in our text
service and dry it here. Additionally, whether
Let's reload the page. And as you can see here,
we're getting weathered, which actually means we
are getting our data now from the service and not
from the controller. Whereas isolated our business
logic inside tech service. But here is one more
important point. We're right in TypeScript, this is why we really need to cover everything with typed. And if we don't do it, then TypeScript
country will help us. What we want to do. We want always to
define correct types. As you can see here inside
our attack surface, would didn't defy
any return types for our find all method. And actually if I
hover on this method, here is column and
array of strings. So this method returns array of strings and TypeScript
understands it on its own. But we really want to provide explicitly what all our
methods are returning. In this case here
I want to say that we're getting back
array of strings. In this case, even if we return something which
is not correct here, then TypeScript will scream. For example, if I'm
writing here return 0, then we're getting
directly TypeScript error. The type number is
not assignable to type string in the
previous example, but won't get any error
because TypeScript just understands that we
want to return here number, but actually we don't want to. We really need to cover
every method that we're using with datatypes and
everywhere rebel also. This is why here we are returned
an array of strings and we want to do the same
inside our controller. So actually when we're
checking this function, we don't know at whole
what it returns true. We can check it here and
understand or even here. But it really nice
to define here that we want to return
here array of string. Then we're always
on the safe side. And here we directly
see that we have a fine old method and it must return the
array of strings.
7. Configuring absolute path: In this video, I want to
talk about absolute path. So actually what I mean by that, as you can see
here, for example, in source main or every file, we have here a relative path. So we have here dot slash
and not some absolute path, like for example, at NUS chess, the same word doing everywhere. For example, in our app module, we have relative path. And this is how it works
by default in last year's, just because they didn't do anything to solve this problem. Now of course the question is, is relative path bed. And I think that yes, it is bad. The main problem is
when I'm, for example, copy paste in this line
and put it in other place, then this input is not valid
anymore because this is relative path which is
related to the specific file. And yes, it works, but first of all, you can
copy paste it from here. Secondly, you can't
replace it everywhere at once because it everyplace
you have a different path. And the third part
is that it's not clear where our file is lying. For example, here we can't
really understand in what folded it can be
insurer with dot slash. We can understand, but if we
have something like this, then we don't have any clue and we don't understand
our file structure. This is why in all projects
I always recommend to configure absolute
path was absolute path. We want to write
something like app slash. And here will be observers if it is inside our app folder. But unfortunately, less GAS didn't do anything to
solve this problem. And there is not a
good way of doing it. Which means actually we must configure
everything on our own. Because everything is just Node JavaScript
and we can do it. But I just wanted to say
that this is not that comfortable as it should
be in normal framework. What problem do we have? Actually all people
just think, okay, we can simply tune here our
Ts conflict Jason here, for example, set here, path. And it is fine because
we have TypeScript. And yes, it will
work, for example, in development mode because
we're using the ts node, which means what transpired
in our TypeScript on the fly. But it won't work, for example, on production because
actually as you saw here, we have a dist folder. Here is all our JavaScript. And this JavaScript
is already transpired and it doesn't know anything
regarding, for example, App Path, which we can
write inside ts config, which actually means our
solution should be flexible. And it should work in both cases with TypeScript and
with JavaScript. So let's start this out. First of all, in
our ts config JSON, I want to add new conflict. Here. We can provide new
property path with S, and this will be the object. Now with the key, we specify
our Alice, for example, here we can try it at
ab slash and a star, which actually means that
we want everywhere to have this app prefix
for our source folder. Now here we can write it
as an array dot source, and here will be also a star. And this actually means
that inside TypeScript for all our files
inside source folder, we have an ls at App. Our next step is to use
additional package module. Allow us if you don't know what this package is doing here, I opened it on npm and
actually it creates aliases for directories and it
registers custom module path. Actually they did is that
we want to use this module only in JavaScript case and
not in TypeScript case. For this, we need, first of all, to install this package. This is where I will
jump to the console. Now here I can write
yarn, add module ILS. And actually you can use here also npm to install a package. It doesn't really matter. The next thing is to create
configuration for module. As you can see here,
we can scroll a little bit and inside package JSON, we can create new
property module aliases and then write all
our analysis here. This is exactly what we need. So Poupon to open
our package JSON, and now somewhere on the
bottom we can create new property underscore
module ILS is, this is the object and here
we want to use an app. This is exactly what we wrote in ts config and here
we have slash disk. So the idea is that
we want to remap all our inputs with an
app inside dot disc. So we have relative path for
our build for production. But it's not all actually when we check
here the documentation, you can see that we must add this require on the top
of our application. So actually we want to add it inside source main
here on the top. But the problem is here
that we don't need this slide at all in
our development mode. When we're running test node, this line must not be there. This is why here I
want to write if. And here we can
write process and. Dot for example, is Ts node. And then inside I
will move this code. So the idea is that
we need to somehow specify in our command when we're calling
our application, this property is Ts node. And when we have this property, this means that we are
in development mode with Ts node and we won't require
module ILS register, but in production we won't have STS node and then this
require will be there. Now, the next step is to provide custom property is Ts node for our starting of application. This is why I want to
jump in our package JSON. And actually here on
the top we have lots of commands like start broad, debug, dev, and start. Actually we need only to one for development,
one for production. This is why I will
remove from here start dev and start debug. And we will only work with
start and start proud, start broad with don't need to touch because as
you can see here, we have just playing
node and here this main, so we're calling main, which is already
transpired there. Now what do we do?
We start command. The problem with that, we
can't really sit here plots environment because it
is a ness start command. What we want here, we
want really to write exactly the same code which
happens inside nested. This is why I will
remove it here and write Eastern node equals true. This part will set in process environment
this property here we have now TS known and this is exactly what we
have inside nested. And here we must specify minus r ds config
path slash register, and here will be source main ts. So your first question is
for sure what is TS node? Actually, this is
the possibility to transpire our TypeScript
in JavaScript on the fly, and we're using it
only for development. Here we have minus r ts
config path registered. And actually when we copy this
part and look for it here, we already have this
package which is installed automatically when our
project was generated. Here is this NPM package. So actually the idea is
that it loads modules from location specified in path
section of this conflict JSON. So the idea is that we must
write this code if we want inside our Ts conflict
json load this path. This is exactly why
we wrote here minus r and here is ts
config path register, and then here is
our starting file. And actually this code will
work so we can check here, I will restart our server
and just run Yarn start, so we don't need dev anymore. As you can see here,
we have STS no true, which actually means
everything that will work. We can reload our page and
we can see the result. But here is a huge problem. But don't have watch here
anymore because we wrote our own command and
it's not watchable. Sum now we somehow need
to implement watch part. For this, we can use a package
which is called non demon. This is the most popular package for deve development when we masked restart our web server when we're changing the file. So actually this is
why I will jump in the console and dried yarn add, and here will be no demon. And after installation
we must create a conflict file where inside
we will specify our command. This is y here inside route, we must create a
node demon dot JSON. Here, no demon dot JSON. And inside we're passing
our configuration. First of all, here we have
watched property and we're specifying that we want
to rely on our new demon. So our web server with when we change something
inside source. Secondly, boop want
here our extension. And in extension we want to provide TS because we're
working with TypeScript. And last but not least
is our exact command. This is the command
that will be executed. And this is exactly
the command that we wrote in package JSON start. So I will copy
paste it from here completely and paste it here. Actually this is
our main command. And now inside start we can
simply call no demon because this will start our no demon locally with this configuration. Let's try this out. I will restart now and
just write Yan stat. As you can see now here we
have logs from no demand. First of all, we can restart at any time by entering arrays. Also, we have watched
in source and everything inside and we're
watching for extension Ts. And this is our command. And the point is that here
now we can use absolute path. First of all, let's
check if it's working. So here I am jumping in browser, reload in and
everything is fine. But the second is if we
have watched or not, this is why I am
jumping inside of a text service and here I
will remove our tag weather. Now as you can see in browser, we don't have a web server. And then after one
or two seconds when demon restarted
our web server, we have our changes. This is why here you
see on loop two tanks. Now inside our survey
you can see that we have no diamond restarting
due to the changes. And this is now our
command which is called again and start
in the web server again. Now let's check that
absolute path is working. So we want to jump, for example, in our app module. And here everywhere we don't
want to use relative path, but we can now write at AP. And here will be the
name of the path. So actually fast at AP
is our source folder. And now we can understand where all these
files are situated. As you can see when I'm writing
something not correctly, TypeScript screams directly
that module is not there, which actually means the
TypeScript understands correctly our ad path that was
specified in TS conflict. And I understand that the amount of changes
that were made in order to bring our absolute path to the life was enormous. But actually, if you
want to use them, you don't have other choice. There are other
possibilities to do this, but they're also not that good. And this is like
the most stable and works for development
and production.
8. Installing Postgres: In this video, I want to install postgres
on your machine, so we have a database
to work with. And of course, the
first question is why I chose port Chris and
not for example, MongoDB, because I know that one could it be easy, really
popular database. And a lot of people who
are developing with known chess liking
and using MongoDB. First of all, you
need to know that there are two types
of databases, actually more, but
to our most popular, first of all, we have
relational databases which actually adjust tables and relations between these tables. And secondly is
document-oriented database, which actually means that MongoDB is
document-oriented database. So actually it is for
storing documents there, which doesn't have any schema and it doesn't have any
relations out of the box. Actually for normal
applications where you have a lot of relations
like for example, users, users can have articles, articles can have comments, then you have likes, dislikes, which means this is relations between maybe users
or posts and so on. These are all staff of
relational database. And true, we can build all
this stuff with MongoDB, but it doesn't make
that much sense for me because we're
getting a lot of stuff which is
really useful from relational database
out of the box. And also we are getting schema, schema validation, all these references and all that we need. And actually almost
always in production, we have a lot of
entities and we want to build relations between
these entities. Ensure I understand that a lot of companies are
using MongoDB in production and they can build relations or whatever
the one there. But it takes more time
and effort and it's not really better than
traditional relational databases. This is why in this course
we will use Postgres, which is one of the two
most popular databases. The first one is MySQL, but I highly prefer
Postgres because it has more features and it is more stable and user-friendly. This is why in
this video we must install postgres
on your machine. This is why I opened
the homepage of Postgres database and we're
interested in Download tab. And actually if we will
click on windows here, you can see download the
installer link certified by EDB, which actually means this is not the official installer
of podcasts itself, but this is the third
party installer, but this is so good that they
wrote it on official page. Here I open this
link on the right, and as you can see, this
is the website of EDB. Actually, this is enterprise DB, which is just a company that is highly using and make
and scalable Postgres. Actually, the idea is that
the heaven installer, which works on all
operational systems. This means that it looks and
works everywhere the same. This is why they have
the recommendation, how we can start
with using Postgres. This is the website
and here we have section for installing
Postgres on Windows, on Linux and on mechanism. And actually it looks
exactly the same everywhere. Here. I just want to shorten the
goal through all screens. But normally it is just download
in your execution file. And then next, next, next set and password finish. Let's check this out. Here I opened windows
and as you can see here, the links for macOS and Linux. So the idea is that first you are downloading
the installer. So you're jumping
here in this link. Here you are choosing your
operational system and truer, you want the last
version, which is 13. So you just don't load here your execution file for
Windows for example. Then here you are
starting your setting up. As you can see, this
is just a window you're clicking Next, you are choosing the directory. You don't need to change it. Now here you have
something that you can select actually from
these four checkboxes where you have Postgres, server, pg, admin, stack
builder and command line tools. You must choose on the tool. First of all, it's
Postgres itself. So this is the first one
and command line tools. Why is that? Because we will use Postgres
inside common line, which is why we
must install them. And after this we simply click Next and then we
have a password. So actually what did this, this is the password
for superuser, which is Postgres user. Here you can say whatever
password you want. Actually 123 is enough. Nobody will care because it is Postgres on your
local machine, but you will need
this password later. Now here we have our
port for Postgres. We don't need to change that. Here located. We also don't need to change. Now we're clicking Next
and here one more next. And here everything
is installed. Actually if you are seen
something like this. So completing the wizard, which means you successfully installed postgres
on your machine. And actually, you just need to come to this step because after this they have the example with pg admin and we won't use it. We will use only
console version. So the idea is that after installing this
Postgres database, it is shining on your machine. And now we can connect to this database from
different places. For example, from
our application or for example from the console. There are hundreds of other
tools and DUIs where you also can connect to database and make something
with data inside. But we want to use console. So here are a few commands. First of all, we're right in
Sudo minus u, Postgres PSQL. What did this? So here we're saying
that we want to call sudo command as
the user Postgres. And actually Postgres is the default user of
Postgres database. Here we're calling
PSQL. What did this? Psql is a common line
tool for Postgres. Actually want inset
console to open PSQL. Here I'm hitting Enter, and here I must provide a password for my
user of my machine. So it's not the
password of Postgres. Here. I'm typing now my password
and as you can see, I'm getting one more message, password for user Postgres. My password here is 123,
so it doesn't matter. You can set it also 2123. And as you can see,
I'm coming to PSQL, as you can see here, hash, which means I am
already inside PSQL. This means that I can do some commands to
connect to my database, for example, or create users
and portraits and so on. If you are seen such window, this means that you installed everything successfully
on your machine. So here now we can use some commands to
check, for example, what databases we have or what users we have
inside Postgres. First of all, we have a
command list or slash L. And this command will
show us all our databases. As you can see here, I have list of databases. Here we have a lot of fields. So actually this looks
like a normal table. And we have here name, owner, and all other fields except of access privileges is not
that interesting faster. As you can see
here, we have named Postgres and this is
our first database. We also have here
two more databases, template 0, template one. We will create our
own database because we need a database
for our project. And the second part
is that we need a user to manage the
specific database because we don't want to use a superuser Postgres
for our own database. And here we can also see the
list of the users for this, we're right and
slash display users. So DU, as you can see here, we have list of roles. Role name is Postgres. This is our first user, and here is all roles. Obviously this is superuser. It can do everything. Now we must create first
Asia, then a database, and then give a privileges for this user to manage
this database. So first of all, let's
create a database. Here I will write
create database, and here will be the name. For example, you may doom clone. Here will need to put semicolon. This is extremely important because this will
end our command. I'm hitting Enter
and as you can see, I'm getting a message
create database. And actually now I
can write here slash list or slash L to
see all databases. And as you can see now we have our new database medium clone. The next part is to create a
user for this word, right? And create user, and let's
name user like our database. It doesn't make realist sense
to name it differently. This is why I will create
user medium clone. And now I want to say
with encrypted password, I want to create a
password for our user. This is why here I am setting password and let's
say here also 123. And don't forget semicolon. I'm hitting Enter
and as you can see, I have a syntax error. So I wrote word
password not correctly. It should be W2 S. Now, when I'm hitting Enter, you can see the
message create row, which means now we can see
all users display users. And as you can see now we
have not only Postgres, but also a user medium clone, which means we
successfully created user reset password to 123 and we created
our first database. Now as you can see here was our medium clone database and access privileges are none here, which means nobody can
access this database. What we must do now is allow our medium clone user to manage our medium
clone database. For this, we need to write
here, grant all privileges. On the database. Here will be the name
of our database. It will be medium
clone to medium clone. And these two medium clone, medium clone is a user
and then hit an Enter. And as you can see, I
have a syntax error. Here is privileges, sir. Now we're getting message grant, which means everything
is working. First of all, what you can see, postgres is really nice
made and everything is superhuman readable
because all our commands is really like an English. Grant or privileges is really a command and we can easily
understand it and read. Now let's check our
databases again. Here I will write
slash L to get a list. And now we see here
our name medium clone, this is our database. And here we have
access privileges. And as you can see here
is the word medium clone. This means that we have
access to this database, which actually means that we successfully
installed postgres, created our first database, created our user, and allow this user to manage
our database. So now we're fully
ready to start typing the database inside our
next JS application.
9. Configuring database: In this video, we will configure our Postgres database
inside our application. And unfortunately, there are lots of ways how we can do it. Let's check this out. The first step here is to
configure type or RAM. What is it? Here I open the official
website, type RM AR. And as you can see here, type where RAM isn't RAM, which can be run in
different places, for example, in node. And this is what is
interesting for us. And we can use it with
TypeScript and JavaScript. And if you don't know
what is our RAM, this is object
relational mapping, which actually means
that this is some kind of wrapper for our database. So we can work easier
with database. And also, for example, type programs supports
different databases. And actually when
we're writing code using type or RAM, this wrapper, then we can use any database underneath that we will specify. This is really amazing. And as you can see here with the official website
off nice chairs and nest GAS works with
different types of ramps. Here you can see
squigglies type RM Prisma connects and so on. But actually toupper RAM
is not that often updated, but it's really stable and well-suited for
production application. This is why we will
use typer room as our RAM for
Postgres database. Now we want to create
conflict for our type ramp. And actually they did
is that we must pass all credentials for our
Postgres database to topo RAM. Let's do this now. For this, I will jump inside our code and here I am
in source directory. Here in source I want to
create new file config dot ts. And as you can see, this is
simply a TypeScript file. And here we want to define a config of type
connection options. And this is really important
because in this case, we will get a lot of
errors because we must specify here all correct
connection options for the database. And after this we
want to export it. So here will be export default, and here will be our conflict. So the idea is that
inside this config, we will provide all
our credentials for database and configuration
for type RM. This is y here
inside I am setting the type here is Postgres, because Postgres
is our database. Now we have here host and
the host is local host. The next one here is our port. And this is the default
port of Postgres. If you didn't change
it in configuration, then it is 5432. Now after port, we must
set here a username. And this is the user
that we created in previous video for our
Postgres database. So our user will
be medium clone. The next one is our password. And as you remember, I said the password to 123. And the last one is database. And other database has the
same name as our user. This is why here we
also have medium clone. Here actually we provided
everything that we need, but I'm getting a strange error. Actually, this error says that I didn't provide
some fields correctly. But the problem is
here that I had an outer input and
it's not correct. We don't import
connection options from NADH TLS where inputting
it from type or a ram. And actually this is
the problem type where ram is not installed by default with nurse
chairs because we can take different
to a ramp system. This is why we need to
jump to the console and right yarn add type or RAM. And this will install a
type of package files. Now when I'm jumping
back, as you can see, I don't have a typo error anymore and this connection
options is now correct. So if I'm passing here,
for example, foo, we're getting a narrower that full property is not
needed to be here, but it is not enough typer RAM is just a library
for using this RAM, but we also need to
install bindings between our nest JS application
and type where RAM. For this, we must
try it here on Add, and here will be at Nest
chair slash tapeworm. This is a package
that was created by Nest chest team and it supports
binding to our typo RAM. Now inside our app module, we must import type
where a module. Here I am writing
type or RAM module. Unfortunately, I don't have here autocomplete
for some reason. And inside we have four
root or a conflict. What it is about, first of all, here is type where a module, this is exactly
the module that is inside this binding
nest GAS type RM. Here. I'm importing it
and as you can see, I'm getting this outer
input from Nest GS type RM. And actually here we're
not writing just a module, but also dot for root. What is four root? If we want to configure our
module or not our module, but a module from the library, we must write dot foe root and we can provide
some configuration. In this case for type where a molecule we must
provide insight, correct conflict to
connect to database. This is exactly this config or ARM config that we
created five minutes ago. Here I want now to import
this herem config, and as you can see
here is relative path. We want to change it to
app slash I am conflict. This is our config, which is just an object whose properties. And here we started
our type or a module, which means our
application should work and be correctly
bind it to our database. Now let's jump to the console
and check if it's working. As you can see here, we're getting an arrows from typo error module and enabled
to connect to database. And here we have a
narrow Postgres package has not been found
and installed, try to install it with
NPM installed PG. So this is what we need to do. We must install Postgres as
a package for our project. This is why I am writing
here yarn add post crisp, and this will install Postgres
package for our project. Now let's check if it's working. Here. We can write arrest to start or just manually stop and
start our web server. As you can see, we're not
getting any errors here because our database
is binded correctly. And as you can see here in logs, we can see a tapeworm module
dependencies initialized, which means it is really binded.
10. Creating tag entity: In this video, I want to
talk about type RM entities. What does it mean? Actually for this, we must check the documentation of topo REM. And actually, as
you can see here, there's something
about connection. We're already made
this because we're connected typo or
RAM to our project. Now we need the part
about entities. So actually what is entity? Entity is overrepresentation
of database table. If you've worked
with other ORMs, normally you hear
the word model. This is our object or entity with which we
will communicate. The idea is that we
define it like here. So here we're defining
our entity user, and here are some fields
that are user has. And now we can do different
things with this user. For example, we can create a new user or save
it to database, find it in database and so on. So actually it
simplifies working with database and actually type or RAM is not part of nas chess, but actually
third-party library. But it works really nice in combination with nash
chess because it also uses TypeScript decorators and similar approaches to create
an entity inside dipole RAM, we must create a class and
have here a decorator entity. Now inside we have NAD always, this is why the decorator
primary generated column, and then we can
create other columns. For example, here we
created column firstName, lastName and is active. And as you can see when
we define such entity, and then we do some
magic type or RAM will create in our database
the following table. This is the user table
because our class is named user and here
are our properties. So as you can see in
the first column, it's ID, FirstName,
LastName is active. Here we have types of data. For example, ID is an int. Here we have var char
because it is a text, and here is Boolean. And we can see here that our ID will be
auto-incrementing. As you can see, we
define not that much, but actually type eardrum did quite a lot of stuff for us. And we don't see
communication with database and all of this
low-level stuff completely. Now let's try and create
our first entity. And for us it will be tagged. So actually, as you saw here, for us in the application, the x is just some
texts and NAD for this, let's jump inside our project. And here we have attack folder. Here we can create a
new file tag, dot n, dot ts and dissolve with entity is actually the postfix
of the file type. So we have controller
module service, and now we have an entity. Here. We need to export our class
and wear a name tag entity. Again, don't forget the postfix. And now on the top we
must use here entity, and this is a decorator and
don't forget round brackets. Now inside we want to write, first of all, decorator for ID. As you saw here in
the documentation, it is primary generated column. So I am writing here
primary regenerated cone. Here, ID is a number just for you to know all a
decent said Postgres, our numbers and not strings. This is important in
the future faster. And secondly, I want to create a column where we
will store this text. So actually we have a
record Dragons for example, and the record CAUTI. We can name this
column name here. What we can write that we have a column and after
we're writing, namestring will know that
our name is string type. This is why we're
storing it here. So actually this code
will create a new table, and this table is named tag. And we will have
the two columns. First of all ID
and secondly name. And this is enough for us in our project because popular
tags is not that huge. But actually after
writing code in a lot of languages and working
with a lot of libraries, normally I like to keep the table names in my
database in plural, so I like to have it not tag, but tax, for example, not user, but users. I really got used to it. This is why I want
the same here. And it is completely possible
here inside the entity, we can provide as an
object some arguments. And here I want to specify a name and the name
will be taxed. As you can see, this is plural, which means this
gigantic will create a table not with
singular tag but tags. Now we need to add two more lines inside
our RAM configuration. For this, I will jump back
in source or ARM config. And here after the
last property, we must add property entities. So entities are exactly
the type of RAM entities. So the idea is that we
can provide them for toupper RAM and then type RM
can generate them for us. And actually it's
not the best way. We will do it on
the farthest start. And then later we will
change it properly. Here I must provide the full
path to all our entities. I want to use here dude name. And if you don't know, directory name is
current directory. And they wanted to
concatenated with a string. Here we have slash two stars, then slash star dot entity. And here I have brackets
and inside dot ds, coma dot js. What is it about? Actually, as you saw, we have here source, so we are here and then say tag, we created file Tag entity Ts. So actually this part
will look for all files, doesn't matter how deep they are with extension dot entity. And actually here
I made a mistake. It should be like
this dot entity. And as you can see
here, we have brackets with dot ts or dot js. This is super, super important because in development
mode we have dot ts and then production
mode in our dist folder, we have done chess. And actually if I'm opening
now dist folder here we have tag folder and
inside tech folder later we will have our
tag entity dot js. This is exactly the
problem because here if performed
try don't chess, then toupper RAM can't find
this entity and work with it. The last configuration
that we want to provide is synchronize. And here is true
what this option is doing every time when we will
start our web application, diapers and Wilson synchronize all our entities and create tables in database if needed to. So now we can rely on
our project completely. Actually, it will be
reloaded automatically, but I want to be
on the safe side. So at this moment, already type RM must
create for us a table. Here I opened again this PSQL tool and we
will use YouTube a lot. As you can see
here, I have hash, which means I'm inside Postgres. And now we want to connect to specific database to see what we have inside
this database. For this we have slash
connect or just C, and then the name of database. In our case, this
is medium clone. And as you can see now
we're getting a message. You are now connected to database medium clone
as user post-class. So I am rude because
we just want to check what information
we have inside. And now we can write slash DT. So display table to
see all our tables. So as you can see here, we have a single table with name tags and type
table own medium clone, which actually means that
we successfully created our new table automatically
from our entity. And of course, we want to see how our table is looking like. This is why we're
saying here slash d, So describe and here the name
of our table, it is tags. And as you can see now this is the information
about this table. This is the name tags, and now we have two
columns, ID and name. Here the type is integer and
here is character version. So we're char, normally this is stream faster
and as you can see, they're both not nullable. But the point is that you
should not know that much about databases actually sure additional knowledge
is always good, but type RM isolates a
lot of stuff for us. And it is easier for us
to work with her RAM and define entities then to work
directly with database. Once again, what is happening? First of all, our
application is configured in app module with typo RAN
module with this ORM config. The most important part here is this entities and synchronized, which means when typo RAM is
starting the application, then it checks all
the sentences and we have our entity tag and TTS. And toupper Ramses this
entity that we created and tries to create this table
if this table is not there, because in our type
program conflict, we provided this
synchronous true. This is why our table
is created on the fly. So now we successfully connected to our database,
created a table, and we can work with our tags and save
them through the ORM.
11. Working with tags repository: In this video, we
will fully finished our first API method,
getting texts. We successfully configured
our database and now we need to start
working with type or RAM. Now I want to show you
once again our request. As you can see here
in specification, we have on the Get Text, this is slash api slash tags, which actually means we have just a request to
get a list of tags. For don't have a
request to create tags, update tags, delete tags, or get a single tag. Which actually means the idea of this project is that somebody, for example, admin,
the very beginning, create on its own in database
directly these tags, which actually means for us
that we need to create in our database several records
so we can fetch them later. Then I'm assuming that
you're not that familiar with databases or
relational little basis. This is why I want to teach
him not just some things, but how to search when
you need something. This is why now for example, we have our open PSQL here and we want to create
several texts. And we can do it here
directly inside the console and just create new
records inside our table, but we don't know how to do it. This is why I opened here, Google and the road create
records, postgres, PS scale. And this scale is important because if you're
using different UIs, it will be different. There is a lot of
nice tutorials and documentation regarding
peer scale and Postgres. This is why normally
you just open the first link that you
have and check it here. As you can see here, you have some information
that in Postgres, we have a word insert, insert, create a
new row in a table. Here with the example
how we're using it, we're right and insert
into here is table name. Then we have round brackets. Here is the list of the columns that we want to feel and hear space values and here also in
round brackets the values. Actually this
construction we will use a lot and this is
the basics of PSQL, Postgres, or actually other
relational databases. This is why I wanted to
jump here in the console. Here I opened pH scale, and as you can see
where I insert in turn, actually it should
not be uppercase, but nevertheless, I think it
is easier to understand what we're writing here is
insert into the table name. Our table name is text. Now we must specify columns. But actually this ID will
be generated automatically, which means here we
must have only name. Don't forget round brackets. You can put here space. This doesn't matter. Now we have one more space
and here is our values. And as you can see in
values inside would need to provide the same values in the same order like for columns, which means this is column one, this is value one. In our case we have online name. Let us provide here,
for example, dragons. Now, don't forget a semicolon. Now I'm hitting Enter. As you can see, we
have an error column. Dragons doesn't exist. And they actually were
getting an error here because we used double quotes
and single quotes. And the idea is that
inside Postgres PSQL, we're using double-quotes
only for names of the tables, for example, but
not for strings. This is why we always must right here everything
in single quotes. So here I wrote dragons
in single quote. Now I'm hitting Enter. And as you can see, insert 01, which means we
successfully inserted inside of a tags this new tab. Now let's create one more tax so we can test with
several texts. Here I am writing
CAUTI hitting Enter, and we'll also go at
the same message. Now the question is how we can see what is inside our database. For this, we also must
write a specific command. The command is select star from, and here will be the
name of our table tags, and here is semi-colon. And when I'm hitting Enter, as you can see, this, the result we have
here ID and name. Here we have 12 Dragons coffee, which means this is exactly our data inside
database in the moment. And this means that
we successfully created two new
records in our table. Just to remind you, things
like selects, for example, or inserts are basics of
working with databases. This is why you need to
master them at some point, but at least for this course, you need to understand basics. Our next step is to get this data inside our
next JS application. So let's jump back inside our application here we
have our tag entity. This is super important for us. We're not working directly with table or directly with database. So actually our idea is that
we're working with database. Only inside our service. This is why we
have tech service. And here we must
use Tag entity to gather with Repository
from topo RAM. The question is, what
is the repository? This is special pattern. How we're getting things
inside our service. Here, how we're doing it. First of all, we
need here on the top to import repository from. And here we have typo RAM. This is directly from taper RAM, not from last year's. Now we want to modify this fined or method because for now we're returning
here array of strings. It doesn't make
any sense for us. We want here to get an
array of our entities. In our case, this
will be Tag entity. Here we can write that we want bag tag entity and
here is the array. But this is not enough for us. Why? Because actually the
operation to get some data from database is a synchronous, which means we must wait until
we're getting this data, which means find all control the return directly Tag entity, but it returns a promise. This is why we're right
in here word premise, and then in tags inside
verite integ, entity. And if you don't know
what these texts are, this is genetics from
TypeScript world. Just to simplify this and not go too deep
inside TypeScript, our idea that for promise, we can specify some datatype
that will be returned. And by default here, if we're writing like this, promise doesn't know what
data we're getting back. We want to specify it, and this is how we're
writing it inside tags, we can write here, for
example, array of strings, or in our case, this is array of our Tag entity. The next step is to
inject here a repository. Actually a lot of stuff in last years is working
with injectors. If we want to use some
additional thing, we need to inject it
inside our service. And normally we're doing
it inside constructor like we did previously inside
our deck controller, as you saw here, we
have constructor here, tech service, tech service, and we will use
something similar here. So I have here a
constructor and inside I am writing a decorator
inject repository. And this is a
special thing as you can see from Nest GAS typo RAM. This is the way how
we can bring type of RAM support in their chest. This is y here we're
injecting the repository. Here we have round
brackets where inside we're passing
our Tag entity, which means we're saying
here that we need a repository which will
work with our Tag entity. Now after this, we'll need to
create our property. Here. We're right in exactly the same like we did
in the controller. So here we have private
than read-only, and here will be any
name in our case, tag repository, because this will be a
repository to work with. Stack. Here is tag repository
and we are saying that this is a repository
of type tag entity. So this was quite a lot of code. But actually you just
need to remember this construction
because we will use this construction
everywhere. If we want to work
with type program, we must bring it
inside our service. And we're normally doing it with injecting our repository. So actually what is repository? This is a special rapper which helps us to work with database. Here we're saying inject
repository Tag entity because we want our tech repository
to work with tech table. Here we're saying that this
will be our local property. The type is Repository
Tag entity, exactly like here we said
promised again to do to specify what datatype
have inside promise. Here we're specifying
that inside repository we have a tag entity datatype. So this was the most
difficult part. Now we're coming
to the easy part. First of all, as I said, our function returns a promise, which means here we
can simply write as sink and then we can
use a weight and side. This is nice because next year support
await and the sinks everywhere out of the box inside controllers,
inside services. And you will see it in a second. Here we said that our
function is asynchronous. This is why inside we can
now call a weight code. This is why here
we want to return a weight because we want
to wait to this request. This is where here we're
saying this tag repository, this is what we injected. And here I have dot, and as you can see, we
have lots of methods. This is actually ORM, this is our wrapper to
work with database. As you can see here we
have find safe count, get ID, whatever you
want, you name it. Now we want just to use Find. And actually as
you can see here, I have a highlight that find, finds entities that
match given options. In our case, we don't need
to provide hear any options. And then this line
will return false from the database all
records of entity tank. Now let's check what we
have inside web server. So let's jump here. As you can see, everything
is red because we're getting an error and enabled
to compile TypeScript. Type promised again,
entity is missing the following properties
from type string, which is actually valid because this error is inside
tech control ts. Let's jump there and
check what we have. As you can see
here, we said that this fine ball must return
an array of strings. This is not valid anymore because we're
using this method, find all from tech
service and it returns back a promise
of Tag entity. And this is actually completely
fine for our controller. We just need to
update our method. First of all, here
we need to write a sink because it is
also a synchronous, because our tech
service dot phi and all is also a synchronous. Here we want to
return a rate and here will be our this
deck service fine doll. Now everything is fine
and we just need to tune this logic because
actual string array is not valid anymore. And here we must write exactly the same stuff
like we did there. Back. We're getting promise
of Tag entity. In this case, we should
not get any errors. Here. Of course we need to
put brackets because we're getting back an array
and not a single entity. So just for you to
know if you are not that familiar
with TypeScript, here we're passing something, for example, let's train. And then this brackets after
means that this is an array. In our case we are saying, okay, we're returning here a
promise with datatype. Again, array inside. This is exactly what
we're getting back. Now let's check it once again. As you can see now we
have a different error. So we are having the era that tech entity repository is not exploited inside our module. This is why we must export it and define
inside the module. Every single time when we want insert module to use typo RAM, we must provide it
inside our module. This is why I will jump
back in our tech module. And here we're lacking an input. Here I want to import
type or a dram module. Here we're writing for
future, not for route. Just to remind you
inside a module we wrote for root
because we're born to, to configure it there. Now inside every module we're running for future
because we need to configure
specifically this module and each module is
kind of feature. This is why here we are
setting for feature and inside we must provide an
array of our entities. In our case it will
be only take entity. So this line is mandatory if we want to use taper RAM
inside our tech module. Let's jump back. As you
can see now everything is green and we don't
have any errors. Now let's hope and browser. And here I have localhost
3 thousand slash tanks. I'm reloading the page and
now this is our answer. As you can see, it looks
different because here we are getting the data
directly from database. And as you can see here, the important part that we
are getting array of objects where we
have ID's and names, so not on the names. So actually we successfully
got data from database, but they're not in
the correct format. Actually, if you open here
the example of our spec, we get a pi tags should
return a list of tax. And when we're
clicking on list of tags here, how it looks like. Actually this is our response. Here we should
have property tax, and this is just a simple array, which actually means
we must write our code in different ways to get
exactly this structure. This is easier to do. First of all, I want to jump
back in our tech controller. And now here I want to prepare our data in the correct format. You might ask Why here and
not inside tech service. So the idea is that inside Service we're writing
reusable things. And normally I'm trying always
to write inside services, things like getting
data from database, not how they should
look for our API. And the Pi view I'm
normally write in inside controller or
if it is to match, then of course we're
moving it inside Service, but you will see it later. Now we want to store this response in
additional property. So here will be constant
texts for example. And now we want to
generate this format. So we can say here return and
here we have property tax. And we just want to
loop through our tags, for example, this map, because this is plain
JavaScript in our case. Here we're getting each tank and we're born to return
tag and dot name. And as you can see, we're
getting really nice outer complete because
TypeScript understands that this is an entity. And here we're getting on the
properties of this entity. This is why here I can say tag name and we
won't get any error. But of course, our final
method doesn't like what we wrote here because
this is not valid. Here. We're saying that we're getting premise of array
of, again it is. But actually we are getting here completely other thing, here, I will remove this
Tag entity array and write this object with tags. And here we have just
an array of strings. And as you can see
now it looks fine, but we don't need to again
to the input anymore. Let's check if it's working. Now, I'm reloading the page. And as you can see, the response is
exactly like we want. So here we have
property tags and inside just the rate of strings, we successfully fully
rendered our data from database through our service
and controller on our API.
12. Creating migrations: In previous video, we
successfully finished our first module
tags because we just had a single request
there, get old texts. This is why in this video, I want to make last improvements for
working with database. And actually I want to
talk about migrations. If we check here inside
source or a ram config, we have here an option
synchronized, True. And actually this option
is really bad one, and it exists only
inside type program. And the DEA is the type
or RAM does some magic and create for us all tables
through our entities. And it sounds all good. But actually it's not. Why? Because normally if we're talking about other frameworks, we don't have such thin
like synchronized, True, we have the thin
which is called migrations. What is migration
they did is that you have your database
which is completely empty, so you just created it. And then you want
to add something, for example, to create a table. In our case, we have
our first entity tags. This is why we want to
create our first table. And actually we're making
it through migration, which means we are creating, you may creation and
inside we create a table. Why it is important, this means that
actually we saved somewhere how we're
changing our database. This means that every
single time when we need to update
something in database, we are migrating our schema, which means we have
the old state and we're getting a new state
through our migrations. Which actually means it works somehow similar to the
gate where you have like commits in
your repository and then you can switch
to older versions. And actually here
was my creations. You always know in what state you're in and what
state will come. Also synchronous
through is unsafe for production because there we don't want to remove any data, which means we must fully
control how we create tables. This is why I highly
recommend you to always use migrations and never
use synchronous option. And if you don't
want to bother with migrations and you want
a short and fast result, you can use synchronous, true, this is completely fine if you just create a project
to make it fast. If you're making real project, I highly recommend you
to look on migrations. If this was theory. Now let's do this. So now we have just a
single entity tags. And this you saw inside PSQL, we have our first table. What we want to do now
is delete this table. Why is that? Because
normally group want to start our application or at
least set up our project. Then we want to create our
database completely from CLI. Then we want to make great all our migrations
that we have. And then we have a
schema of the table. This is why the first
command that we need is db drops or
dropping the database. And actually for testing
or for development, it is truly important
and useful command. Let's jump inside
the package Jason. And here we'll want to
use type or amyloid. And tau typo RAN module is
situated inside node modules, but we don't want in every single command to
use Node modules path. This is why here we can create an additional command
which is called taper RAM. We won't use it directly
only inside other commands. So here we can say ts node because we want to
use it through TypeScript. And here we must add this attribute minus error
ts config path slash register because we want that all files have our paths
that we specified. Now here inside we must provide a full path for
Selye of type RM. This is y. Here is
node modules slash taper around slash CFLAGS. Now we must specify our config that were
already created previously. This is where here we're right
and minus, minus config, and here will be source
slash or a ram conflict. Yes, we're just saving it. As you can see here,
we must use ts known because we provide
in here Ts conflict. Now, when we create
new commands, we can always use
this taper RAM and it will be with TypeScript
and risk correct conflict. Here I want to create first command dB drop
to drop the database. So as this type rm command is inside scripts
in package JSON, to use it inside every command, we must run it through
NPM or through yarn. This is why here I will
write yarn and tapeworm, and this is the usage
of this command. And now here we can
specify something, for example, schema drop. And they actually
inside type or RAM, they already have this
command schema drop, and it will delete all
tables inside our database. And this is exactly
what we want. So now I can jump inside shell and just write yarn dB and drop. And this will remove all
our tables inside database. This you can see we are
getting here nice slog, so we have transaction and
here is drop view and so on. You don't need to
fully understand it. Of course, if you can, then it is easier for you to
debug your Postgres later. But actually for
now we can see here the database schema was
successful at dropped. This is why if am
jumping now inside PSQL and I'm writing
just slash DT, I don't find any
relations because our database is completely empty and we don't
have any tables. The next command is to
create a migration. So actually we have our first entity tags and we want to create a
migration for it. This is why here we can
create new command db create. And just to remind you here, I prefix all commands
with database with dB. This is why it is
easier to use them. Here we also want
yarn type of RAM, and here we want
to use Migration. Generate minus minus
minus n. The idea is that this is the attribute inside
we can provide a name. Now let's jump in
source CRM config, and first of all change the synchronized from true to false. The next one is to provide
here a migration path. And we want to store all our migrations in a
single place inside source. This is why here we will
have slash migrations. And here we will
have star, star, star dot, and here will be our extension dot ds, n dot js. And if you are asking why we
have this strange extension, because this line must work in TypeScript and in
compiled JavaScript. Either it is inside source with this directory name
or it is inside this. But it is not enough because we also need to provide a
configuration for CLI. So here we have an option CLI and inside migration directory, here we must have
source migrations. So this will be our
future directory. As you can see, these
lines both i important for our migrations and of
course synchronized false. Now let's check if it's working. First of all, I want
here to use again yarn dB drop to be sure that our database is
completely cleaned. And now we're right in here, yarn TB create, create tags. And in this case with
our new configuration, our migration is being created
inside source migrations. Here is our unique ID
and create test.html, which means we successfully
created our first migration. Let's have a look
what we have inside. Here. Inside Migrations folder,
we have this new file. As you can see here, we
have a class grade tags implements migration interface
for us is important. First of all, their name, this is just a unique hash. Here we have two
functions up and down. The idea is that here we can always roll
back our migration. Which means here we define
what our migration is doing. This is our app. And if we want to roll back it, we can use down. Here is the code. So here we're using query, run our query and we are
using create table tanks. And you can understand from
this code what we're doing. Actually this line
creates for us tax table. The most important
part here is we don't have any magic
inside type or IRM. We really see what typer RAM is doing for us
through migrations. And here we can even change something if something
is not correct. Actually, the whole code
that you can see inside the strings is
Postgres native code, which means I can
copy it from here, paste inside PSQL and
execute, and it will work. So here we're saying
create table, which creates a table
with name tags. And here we have round brackets. Here we must provide our column
names and then the type. Ensure you should not understand on a 100% at the beginning, everything that you
have inside migrations, you can simply execute them
and then they are working. The most important part
is that you can learn it later and always check and understand why
it's not working. So actually we successfully
created our migration. And now we know that
here our migration was created based on our entity
tag that we changed. Now the question is how we
can execute this migration? Because normally when we've just set up the empty database, we want to apply there
the correct schema, which means we need to run
our migrations that we have and generate the latest
version for our schema. And this is why we're jumping
back inside R packages. And here we must create a new
command to run migrations. This is why I am
saying db migrate. Here will be yarn typo RAM. Here, migration Run, migration, run command executes
all our migrations in the correct order. Now let's jump into console. Right here, yarn db migrate. And migrate doesn't
create anything. It executes all migrations. So here we have lots of
logs if you are interested. And here the most important
part for us is that inside migrations we have
this line create table tags. Which means after
running our migrations, our table was created. And now we can jump inside
our PSQL and right here duty. And as you can see, we have
not one table, but to, first of all, we have our tags which is
correctly created. And secondly, we have now a
table with our migrations. Let's check what we have inside. Here. We can write select star
from migrations, semicolon. And as you can see now we have only a single record
here with AD. This is the timestamp when
our migration was executed. Here, read the name. Why do we need this actually
type program control and know what migrations
were executed. So at the moment when we're
running yarn db migrate, diapers need to check what migrations are there
already in database. This is why here it
is storing them. We don't need to do anything
with this migration stable, but diaper RAM will use
this information to understand what migrations
it needs to execute. Once again, what we did, first of all, we removed
this synchronized false. Why we need to
remove it because we don't want any magic
from typo RAM. Second, Lubert added
here configuration for our migrations and created our first migration
for our tags. And when you want to
create a new Migration, dipole room checks in
what state our table and database is and
what entities we have. And if we have something
different than this, changes will go in
this migration. This is how our create
decks was created. Now I want to short-lived
goals through the whole workflow
using migrations. So first of all,
we're committing all migrations because they
are a part of the project. Which actually means
every single time when you are changing database, you create new migration. And this is a mask. In other case, you don't know
what you really changed. First of all, when
you want to run your project on the new
machine, you clone it, install all dependencies, and then you want to do migrations. This is why you just
execute yarn db migrate if your
database is empty, if not, normally you
want to make first young to be dropped and
then yarn db migrate. And actually at this
moment you will see that I don't
have any migration. So here you can see
no migrations are pending because our database
is in the last state. When you are doing production, you normally will clone your projects there
or maybe deploy. And then you also want to
execute their migrations. And if you want on
production later to change the field or
maybe to add new table, then you simply locally create a new Migration and then you execute this migration
on production. And you are sure that you
won't break the database. Because inside migration, you really know how you are
changing the state. So migrations are a must
for real-world projects. This is why we will use
them for all our entities.
13. Preparing register request: In this video, we're starting to create our new
module and new API. This is the
registering of a user. Let's check this out. Here. I opened our requirements. As you can see, we have here a registration part and
this is the post request. So we're creating a user
for slash api slash users. This is the example
of the request. So we have an object whose property user
this is important, so we're not throw in all
fields just inside rude, but they are inside user. Here we're biasing the users
name, email, and password. And of course all these
three fields are mandatory, no authentication required, and we're returning back a user. This is how our user
is looking like. So it is looking like this
across the whole application. Here we have an object
with filled user, and here's our e-mail
username, biography, image, and talking about token, we will talk later, but this is the raw thin
that we will implement. Solid start coding. I will jump back
inside our source. And as you can see here, we have our tag module. So actually all
requests which are related to tags
were right in here. If we're now talking
about authentication, it makes sense to create everything in additional
module and we can call it, for example, user,
because actually registration is just the
creation of the user. This is where here I
will create new folder, which is called user. And as always it is singular and inside we're
registering module. And if you don't know how to
do it or you don't remember, you can always open on
the right tag module, for example, and copy paste
almost everything from here. But I highly recommend you to
write from scratch several times so that you understand and know
what you are writing. Here we want to expert our
new class user module. Here on the top of this
class we must write our module were important
module from last year's common. And inside we're passing an
object with some things. Now we must register our
module inside module, because in other
case it won't work. This is why I am jumping
inside f module. And here I am importing
our new user module. Here I have autocomplete and
as always, it is relative. I want here absolute path. We successfully
created our module. The next step is to
create controller, because without
controller, we don't have a place to write
somewhere our API. This is why here I am creating user dot controller dot ds. And inside we're creating
also export class. And here we will have
user controller. On the top. We must add here a
decorator controller. We're inverting it, and now we can create our new API methods. Now here is an important point, as you remember
here inside tank, we wrote and said controller
on the top, these tags, we specify that all
our methods here inside must be
prefixed with stacks. But this is not
always comfortable. Why is that? Because if, for example we want different paths for
different requests here, then we should not
write it here inside controller because it will be then global for
this controller. What we can do, we can manually specify a path for
our average request. We're doing here, the
creation of the user. This is why I want
to create here a synchronous
function create user. For now we don't know what we're getting and what
we're returning. Actually, we can write
here promise any, just to see that we didn't specify here any interface yet, and we must create it. The next step is to specify
what type of request it is. And this is a post request because we are
creating the user. This is why on the top I
am writing a decorated posed by importing
it from Nest chairs. Now of course we're
master returns something here for now
we can simply return, for example, a strain create user just to test if everything
is working correctly. Now we can jump inside our server and see if
we have any errors. There are no errors here
and here somewhere. And we must have
our user module. As you can see here, the line user module, which means that we are
binded it correctly. But there is one more thing
that we forgot to do. As I already said, we didn't say here inside controller what route
Groupon to use. This is y here inside post, we must specify this route. In other case, this
will be posted for home URL and this is
not what we want. What we want here is
slash users because we want to make post
request on slash users. And this is exactly what is written here inside
registration. So it should be slushy
by slash users. This is why here I wrote users and it is valid only
for this request. And if we will create
some other requests, we can provide
different path here. Now let's check if it's
working with Postman. Postman is our bread and
butter to test requests. As you see here, we have some URL
that we can type, in, our case, localhost
3 thousand slash users. This is fine. Here we can choose
what method we want. Here we want to post. We can also provide
here lots of stuff. We don't need it now, here I want to click Send. As you can see here we're
getting cannot find both users and
this is not found. This is really the mistake that people are
doing super often, especially when they're just starting to work
with nice chairs. And the problem is here that
it's not just not working, it just forgot to bind our
controller inside module. Let's jump back
inside our module. And here was user module. Inside our module we must
write controllers array, and inside create
user controllers. And of course here
we will have add ab slash users slash
user controller. Now when we try once
again, it must work. As you can see here after sand, we're getting the
message create user, which means our API
is correctly created. Here is one more important
thing that I want to show you. We will do a lot of requests. This is why we really can't
type every request here. We want to save them. And in Postman, even
in the free version, we can use collections. So actually here I can create
new collection and name it, for example, ness chess. Now inside I can save
all our request. And it's not that comfortable
to make it here with plus, but we can jump back
inside our history. Here is our slash users posts. And we can just say here
Save and here we As. So we want to save as, and this is the request name. So we want to name it register just to know
what we are doing here. Here is our collection list
just here I am clicking Save. And now inside
collection, Let's js. We can always click Register and this request will
be out of field. If we change it with some data, then it will be also saved here. The next thing that we want to do is to create our service. So actually we don't want to write our business logic
inside controller. This is why we will
create user service. Here exactly like in tags, we have a service and here we first of all need an injectable. And after we're experts in
our class User Service, now inside we can create
a method create user. This is why here I am right? And create user exactly
like in the controller. If you don't know yet
what we will get back. But here at least I want to return create user
for Rome service. Why is that? Because
in this case we can first check if we bind
it everything correctly. Here is our user service and we must registered
inside user module. This is y here,
result providers, and we're right in
here, user service. And here is our input on
the top with ab slash user. So our services there. Now we need to jump and controlling and do
import it here. Again, if you forgot
how to do it, you can always underwrite
open our tech controller. We wrote exactly the
same logic here. Here we have our constructor. And inside the constructor
as an argument, we need to write
private read-only, and here will be
our user service. And the name is user service. We will do exactly the
same impulse everywhere. So you just need to remember this one line here in the
import I have slash slash user. And they think I will stop to change this relative
path to absolute path. Because you already got the idea that absolute
path is good. Now here instead
of our great user, we can call this user
service create Houston. And in this case, we don't
have any business logic inside controller
Bot Insight Service. Let's check if it's working. I'm hidden sand and here we're getting create
user from service, which means we
successfully configured everything to start developing
our register module.
14. What is DTO?: In this video, I
want to talk about D2L in this chess or
data transfer object. And this is really simple. So normally when we're
making, for example, post request, we have the body. And actually this party is
named DTO inside knees, chest. Here the documentation we're inside controllers and detail
is data transfer object, which actually means
this is a schema of the payload that we provide for our
back-end, for example, were registered user
here we can check it as you can see here,
there's registration, all this stuff here is
actually our detour because this is the object that we're sending inside backend. So you might ask why
it is important. This is simply pay Laude, simply body and
we're throwing it. Yes, but we can validate
detours inside nice chairs. This is first one. And secondly, actually DTO is a class and not an interface. Let's check this on the example. Here we have our create
users here are exposed. And actually what we want to do, normally we want
to read body here. And actually we have a special decorator to get
boarded directly from request. Here inside create user, we can write directly
at decorator. Here we're writing body, as you can see here,
result or invert. And then side round brackets, we're right in the name
what we want to get y, because actually we
don't care about this property user and we really want to just
get this data. This is why here we can
write user and then we're not getting the
whole body but just using, this is really convenient. Secondly, after this
decorator will need to provide the name for
our local property. And actually I will
name it create user DTO just because they
don't want to have some strange naming
and will know, okay, the request
is create user, and this is the payload
of create user request. This is y. Here is
create user DTO, and for now I will write
it here as a type. The most important part that
this is a local property, which is just a body of user. And now we can
pass great detail, for example, inside our service. But for now I will simply
console log it here. This is create user, and here is create user DTO. Now we need to pass something
inside our request. This is y. Here I'm clicking on Body tab. And here we are
interested to select row by row because here
will be a plane JSON. We want here adjacent
with field using it. Now inside the user we have an object with
several properties. First of all is our username. So here we're right
in the username. And this is, for example, full. Then we have here e-mail, and this will be
full at gmail.com. And we have here, our password. Here will be 123. The most important part
is that this is adjacent, which actually means you
must write here quotes. In other case, it won't work. Here. You can select this as JSON and then you will get
a nice highlight. And actually here,
as you can see, I missed the quote. So this is how
we're passing body. Now I'm hidden sand and we
must look inside our console. As you can see here, we're getting
consoler create user, username Fu, email password, which means we don't
need to do anything. We don't need to install
additional packages. Like for example, with Express, we're getting all this stuff out of the box
inside nice chairs. We have this decorator
body and this is how we're reading body
inside our requests. So actually to make
it more realistic, we can pass inside our
create user function, create D2L, and then we can
jump inside our service. Here we know that we're getting create DTO for now without time. This is why here
I am writing any. Here we can return our create the term just to see
what we passed inside. Here, let's jump in Postman, I am clicking Send, and here we're getting
our data back, which means we pass them inside service and
everything is good. Now the question is how we can
write a type for this DTO. And as I said here
in set controller, we don't want, of course, any book Born to
specify an interface. But here is the problem. There is a difference between an interface in
TypeScript and the class. Interface is just a datatype and to just exist
inside TypeScript. So it doesn't exist inside
the runtime in JavaScript. But classes actually exists in JavaScript because this is just prototypes and
they have been cold. This is super important for us because we want
to validate them. This is why here it doesn't make any sense to write
just an interface, but we can write here a class. What I want to do here is to
have a class create user, DTO was big C. Now we must create here
a new folder duty on, and here inside we will
store all our details. And here we can name
the file create user dot dto, dot ts. So actually the
TOR is our entity. And now inside we
simply create a class. This is nothing special. There is no magic here. So this is just a plain
type script class was no less chairs. Here we are saying that
this is create user DTO. And inside we can write
several properties. For example, we
can say that here we have read-only username. This is type string. Then we can create
read-only e-mail. This is also type string, and here is our
read-only password. And if you're asking why I am right in here read-only because actually this is the payload and we should not
change our payload. Now we can use our class that we created
inside controller. So here I will import it on the top and now visit the class. So we're passing inside
actually the deuterium, which is our class. Now here we're
passing it inside and we can also use it here
instead of Fannie. Here we're getting
create user detail. And actually it won't change
anything from the code. Because here we just
specify that as a datatype. We can check that this
is still working here. Send, we're getting
the same data back. But the point is
that later we will validate data inside this class. And this is exactly
the idea of detail.
15. Creating user entity: In previous video, we
prepared everything that we need to make
our register request. Now it's time to start
working with user. And actually we always must plan our application by entities. For example, we have an
entity tag and denote case. It's even easier because we
can always jump here inside our specification and check all entities that
we must implement. In our case, for example, we have an entity user later, also profile and so on. Now we want to create
an entity user, and this means that we can
operate with this entity. For example, we must create a table where we will
store our users. Also, we can get
user, of course, save user registration or
maybe update currentUser. In our case for this, we're doing exactly the same
lake with DID insight tag. This is why I want here to open our Tag entity on the right
and on the left-hand side, the user, I will
create a new file, user entity dot ts. And this is where
our user leaves. And this is the entity
by which type of RAM will create a table for us. And we will of course
do migrations. What we want here is export class and here
we have user entity. Here on the top we must
write and decorator. And here we're saying
name users because I want my table to be not user
like this entity but users. Now let's create all
properties inside will always need here a
primary generated column. This is our AD and we know
that this is a number. Now here we will
create other columns. As you can see here, we have e-mail token we
don't need to store, we will add it later, username, biography and image. Here. First of all, we can
say that we have column and it will be our e-mail
which is a string. Now also we need biography. So here will be also column with round
brackets of course. And here is biography
and it is also a string. But here it makes sense
to set a default value. And we can say that this
is an empty string, in this case in front, and we should not
check if it is now or string will always
store here string. This is why here we
can say default. And as you can see here, there's autocomplete
of TypeScript for us. And here I am saying
an empty string. The next property that I want
to store here is of course, our image here will be column, and we can also set the
image to empty string. This is y here will be
default empty string. And here is our image,
which is string. And actually in our case, image is not truly an image. This is just the URL where
we can load the image. And last but not least here
is of course a password, but we don't want to store it. Just like we said, it inside the forum
would want to hash it. This is where here I will
add one more column and we know that this will be
password and it is string. But now we don't want
just to save it here, but we wanted to generate it. For this here on the bottom, we can write before insert. And as you can see before
insert this as a decorator, which is a method. And this method will be called
when we make an insertion, which means after creation. Here we are right
in, before insert in here will be our function
which will be assessing. And we can name it how
we want, for example, hash passport, because this is exactly what
we're doing inside. Here. We can write
this password. Here, we must hash it. So we need to install additional library for
hashing passwords. I highly recommend you
to use decrypt library. This is the most popular
library, as you can see, to encrypt your password
from this library, we want to use a method hash. Here's the example
how to hash password. We're calling decrypt hash. Here is our plane password
that we wrote in our forum, and here is the salt solve. This means how many times
it will be encrypted, then we just get a callback. So as you can see, this is
an asynchronous function, which means we must
write it with a weight. Now let's jump into the console and then style be
gripped package. So here is, I'm in console
yarn AD via decrypt. It is being installed. Now we can jump back
inside our editor. And here on the top, I want to import function
hash from decrypt. Now here we must use it. And this is important
here that we wrote as sink because hash
is a synchronous. This is why here we
must try await hash. Here inside where bison, this password, what
did they actually, this password is the
current password that we wrote inside form. Why? Because when
we're calling save will have all these fields
and we have our password, and we want to override it with the hashed version
of our password. And here we also
must provide a salt. This is where here
I am writing ten. Now let's check if
we have any errors. I'm jumping here
in the server and as you can see,
everything is green. So actually this is
our new entity user, which will be stored
in our table users, which we will create through
migrations in a second. Now it's time to
create a migration. And just to remind you, we have some state
of our database. Here we can jump in peer scale. And right here, we can see
here migrations and texts. Actually at the moment when
we will create new migration, our typo room will
understand that this is user entity and it's
not in the table yet. In this case, we will
get this information regarding this user entity
in the new migration. So just to remind you, inside package Jason, we have
here the command db create. So let's jump inside
console and dried yarn, and here will be DB create, and here was previously
create tags. Now we can write create users. We're hitting Enter and our
migration is generated. As you can see, we are getting message generated successfully. Let's check what we have
inside source migrations. We have new files, create users. This is our command. As you can see, it
looks really the same like our
previous migration. We have here up and down. So down is to roll back. This is y here, drop table
users, which means delete. And here is our create
table with all our fields. So as you can see, all
these fields are fields that we specified already
inside our entity. And actually, if you
have some questions, what here is happening,
for example, you don't know what is create table users or Cyril
not null and so on. You can always google some
partial part of it was worth Postgres and find
lots of information for us. Now it's not that
relevant because we will work with our tables and see
if something is not correct. But this is of course nice to know for better understanding. Actually, I'll migration
was created and now we must execute it because it was not
applied here to our table. This is why I am writing yarn db migrate and this master
apply all our migrations. First migration is
already applied. And here as you can see, we have new code. Here is our create table users, which means our table was
successfully generated. Here I can jump now in
PSQL and dry the teeth. And as you can see here
is our user's table. Here it is, and we
can describe it. So check all its schema. And as you can see here, our columns ID,
email, biography, image, and password, which means this is exactly
what we wanted. Now we're actually almost done. We prepared our table. We have basic code, was our controller here. Let's check this. We have user controller here. We're getting our body
from request and we're passing this create user
details inside or service. So the only thing that we're missing is inside the service, we must write some code to create our new entity
user and save it. Let's do this now we don't
need here return detail, but instead we want
to create new entity. This is why here we need
to write const, new user. In here is new user entity. This user entity
where expert mean exactly from our file
that we created. In this case, new user is exactly the instance
of our user entity. So actually it doesn't have any fields inside
what we want to do. Now, we want to write inside this object all fields
from create D2L. And actually this
is really easy to do with object assign because we want to have this new user as a property and not
create a new one. So we really need to do
everything mutable and immutable. This is why here I am
writing object assign, and here will be my new user. This is what I wanted
to overwrite and I'm overriding it with
create the Tiana. Actually I don't
like the name create detail because here is
create user detail. This is why I think
create user detail here is better and more clean code. Here we assigned all
properties now from create user inside our new user. And actually we
can console log it here so we can check
what's going on. Let's try it here in New User, and here is our new user. Now we can just jump inside
Postman and make our request. So here I'm hitting sand, as you can see this as
our previous request. Now we must jump to the
console and check it. As you can see
this as new users, this is user
identity and we have all these properties
that we got inside. This is all fine
and we just need to save now this user identity. What we want to do here is
return a weight because always saved into
the database is with a weight because this is
a synchronous process. And here we can use
this user repository. And just to remind you,
what is repository, this is exactly the way how
we're working with oil RAM. We already did it
inside tech service. Just to remind you here
with the constructor, with injection, we must
do exactly the same here. So we are writing constructor. And here there's brackets. And inside we have our
inject repository. And inside we're biasing
now our new entity, user entity because we're
working with our user. Here we have our private
read-only property, and here will be our
user repository. We're saying that this is
repository of type user entity. As you can see, code
is a 100% the same. We just copy, pasted
it and change here the entity and entity
inside our repository. Now here we can use
this user repository. For this, we're
right in here away. It uses repository dot and we
can do, for example, save. And this is exactly
what we want. So it saves the entities
to the database. Entity is our new user. Just this single line, do all magic and saves
our user to database. This is why Rams are so awesome. You should not know SQL, you should not understand fully how to make requests
to the database. You just use a wrapper and it works like magic
out of the box. Let's check if it's working now. I will jump inside
postmen and click Send. And as you can see here, cannot send the request. And normally we're
getting this error. If something is broken, we must jump and said Sarah, and check what we have. And as you can see here, our problem is that
nest countries of dependencies of
the user service, which actually means we provided something
inside user service, but nest doesn't know
what to do with it. And our problem is, of course, this user identities
repository because we forgot to add dipole ramp
input inside our module. So just to remind
you inside our tag, inside tech module, we wrote this line typo REM module
for future Tag entity. But inside our user module, we don't have this line and this is exactly the problem here. We must add an import. Here inside we have type
or module dot for future, and inside we have
array of features and in our case it
will be user entity. In this case, we can
inject repositories with user entity and use it inside. But for example, Tag entity, we can't use it because
we didn't injected it. Now, let's check
if it's working. I am jumping and say
postmen, I'm hitting sand. And as you can see,
this is my answer, which actually means
that this is working. This is actually our user from the database that
is already saved. Here we have username, email, password, and the password
is already hashed, which means we're not storing passwords as plain and
we should never do this. Here is our AD. This was generated by database and biography and damage
we didn't provide, which actually means
all information that we give inside our
payload is there. And due to saved, we can of course check it
inside database. So here I am inside PSQL and
I can write select star, which means all from users. And here I am hitting
semicolon and Enter. As you can see, this
is our new elements, so we have a D1,
here is our email. We don't have anything
in biography and damage, and here is our hashed password, which actually means that
we've successfully created a user and saved it
inside the database. Now, I just want to fix
typings a little bit. Actually, let's jump
back inside our service. And here, as you can see with don't say what we
are getting back. But actually when we
hover on this function, you can see that here as an
argument where getting create user detail and back we're getting promise of user entity, which actually means user entity is what we are getting back. This was created and TypeScript understands
all of the staff, but I highly recommend
you to always explicitly say what
you want to get back. In this case, you
will get an error when it's not like you expected. This is why I am
saying that I want back a promise with user entity. Now let's jump inside
controller and do the same. So here we specify that we're
getting back promise any, which actually is not
true here we have promise of user and here is entity. We're specifying
everywhere our entities. And as you can see, we
don't get any errors. But actually this
is not correct. Because if we jump in RSpec and here we can
see the response. The response is the object with property user
and feels inside. And as you can see
here, instead Postman, we just get all our fields
and not what we have here. This is one more problem
to fix in the next video.
16. Generating jwt token: In this video, we must
fix two problems. First of all, as you saw
in the previous video, but don't have the correct
response because I will response is packed in
additional property user. This is not that
difficult to fix, but we also have here a token. And what is token? This is a DVT token which
is used for authentication. The idea of DVT is
that our back-end generates some token and then on front and
we're saving it, for example, in the cookie. And then this cookie is being
attached to every request. And in this case, our backend nulls
What request is coming and what user is
making this request. In this case, we can give
the correct data or make, for example, forbidden answers if the token is not correct. This is exactly what we
will do in this video. So actually the main
problem that they see is if you are Google
and gt for example, you are getting all articles
just about post-purchase, which is kind of a little bit complex and not that low-level. And actually we will build, GET on our own
because it is super easy and we don't need any
additional dependencies. For this, we will use a package which is called JSON Web Token. This is the most popular package to generate our GVD string. This is why we're jumping
inside of our console. And here I am right in yarn, add JSON Web Token. This will install this package. Here we're interested
in the methods sign, as you can see here is
usage DVTs sign in payload. We can pass whatever bond. Here we have a secret key. The secret key is
super important because this is our
unique secret key, which nose on our back-end. And then this function
will generate for us a string that we must bass
bag for our front-end. So let's check here. First of all, as you can see, my package of JSON Web
Token is installed. I can jump back
inside O controller. Here. We must do this inside
our Create User Service, white there, because
I don't want to pollute our create
user controller. And normally weld right, and all business logic
inside our service. So actually we can write this logic directly inside
create user function. But this is not good because we want a separation of concerns, which means actually create user function is
really super plane. It just gets the duty
OR and gives us back user entity and we're not storing inside database
attributed token, which means this function is not the best place
to write this code. What we can do here, we can create a new function. It's not even a sin k thing. And here we can write build
user response y like this, because actually we will build the response for our front-end. And actually inside we can write our code to generate
this kind of response. So what I want to
get here is a user, and this is our user identity. So this means that
this function we will call not
inside create user, but inside the controller after
we're already get a user, hear back for now, I will just return any and we will fix it
in five minutes. What we want to do inside, we want to build our
correct response. So here we have our user. And for this we want to merge all fields from the user
of width, the token. Why is that? Because this create user function is generating
false user entity. So actually all these
fields except of the token, which actually means
we must spread here all fields and then add token. In this case, I'm spread
in here our user. And then I'm adding here our token which actually
must be generated. This is where here
we already need one more function which will
generate for us a token. This is where hear
this Generate token. For example, maybe generate GBT. And here inside where
bias in our user. Now let's create this function, generate GET, which
is getting a juicy. And we know that this is
user entity and back it must give us a string because Judy token
is just a string. Now this is fine. We have this built
user response. Now let's use it
inside our controller. First of all, here, we don't want to just return everything. We must first save it
inside some property. This is y, here is user, and here of course equals sign. And now we must return
here our new function. So this User Service
build response. And as you can see, I called
it build user response, which actually is
exactly what we need. We need here to build a
response for our front-end. And inside we're
biasing our user, which is a user identity. And as you can see here, we're getting
directly and narrow. So the error is the argument of type promise user
identity is not assignable to put a meter
of type user entity. The main problem is here that I forgot to write here a weight. This is way back inside user. We're not getting user
entity, but a promise. And TypeScript really helps
to fix such problems. So now let's jump back inside
this build user response. And check if it's
working actually here, generativity doesn't
do anything. So let us return here,
for example four. So at least we can see
that it is compiling. Here I'm opening Postman
and hidden send request. As you can see now we
have other structures. So we have here an object with user and all our fields here, which means this is
exactly what we wanted. And we even have here
a property token, which is a string form. Now we just need to generate Gvd token by using a library. So let's jump back inside our service and dried
this generativity. For this, we must use from JSON Web Token this
function sine. This is why here I will import the function sine from and
here is JSON web token. Now here inside
our generativity, we can write return and call
here our sine function. The main point is
that inside pay load, we can provide whatever we want. And for us it is important to have some useful
information here. This is y here I want
to write inside. First of all, AD, this is
our user AD, then username, because we can render
this information on the front end here,
this user username. And here maybe an email. Here we'll be user.email. And actually as you can see, we don't have username, which means we forgot to
create it inside user entity. But we will fix it in a second. Because here we must
for sure use username. And the last thing that we
need here is our GBT secret. As you can see here, we
have some secret key. So this is the key that we must use and know on the backend, we can write here for
whatever you want, but I really prefer to save this stuff
inside some conflict. This is why inside source, I want to create new file
and call it conflict dot ts. Here we will write all
such global properties for our server. Here we can write export const. Here will be the name, for example, GBT secret. Here inside you can write
whatever string you want, for example, super secret. So our string is there. Now we can use it instead
of just plain stream here. So I want to write
here, GET secret. And of course I got my outer input here on
the top from AP conflict, which actually means this thing will generate for us as stream. But now we have a problem
with this username. But we can't really
just write it inside an entity because it's
not inside the migration. This is why we actually must
create one more migration to add this username property
inside our database. This is why I wanted to
jump and say user entity. And somewhere here we're
creating a new column. And we're saying that this is username and this is a string. Now we must generate
in your migration. Here I'm jumping
and say Shell and I'm right and yarn db create. And here will be
not create users, but maybe add username to users. So we really want the name to be understandable what
we're doing inside. As you can see, our
migration was generated. Let's check what we have inside. Here we have our third migration
and username to users. And as you can see here is on
the one line, alter table. Alter table means
change table structure. This is why here we have alter
table users add username, which means this is
correct migrations. And we're adding a
new column username here inside our users. Now we must call yarn db migrate
to apply our migrations. And as you can see,
actually record an arrow. So credit failed and colon username of relation
users can tell null values. And before we will start to
dig deep inside migrations, I highly recommend
you in this case, to just remove everything, the whole database and apply migrations again,
this might help. In this case, we're not spending time by the bike and some magic, but simply remove everything. This is why yarn dB drop. This will completely drop the database and
then Yan db migrate. We'll add all our migrations. As you can see now, all migrations are working and we don't have any magic errors. And actually this problem was
because we already created the inside user and this user didn't have
the correct schema. This is why the best
way is always to remove your database completely
and regenerate the schema. Now let's jump back and say though a Gvd servers
and finish it. Here I am opening our
user, User Service. And here as you can see, we don't have any error
and they actually were successful at generated
distributed team. So we simply call a function, we don't do anything. And this function is
being called here. As you can see, we
don't have any errors. So let's try and
create new user. I'm jumping and said Postman, I am hidden sand. And this is our answer. As you can see, this
is our new token, which is exactly LGBT
generated token. Which means we
don't do anything. We simply call a library. We provide there a secret and we're getting
back this token. Now we can safely give this
talk into the front end. And this is exactly
what front-end once. The last thing
that I want to fix here is of course our datatypes. So if we are jumping
back, as you can see, we have here any and
of course n is bad and normally want to create
here some interface. So I highly recommend you for all responses to
create an interface. In this case, it is easier to
understand what's going on. And we don't create
here a detail like we did because we're using
detours only for payload. What I want to do
now here inside the user is created
new folded types, where we will store
all our interfaces. Now here I want to create new
interface for our response. This is why here I have used the response dot
interface dot ts. And inside I will export here an interface, user
response interface. Now the question is what
we're writing inside? The main point is that here
actually in this spec, we have inside the entity. And additionally we
have here a token, which actually means
this interface is a mix of entity and our token. We can solve this problem by
some advanced TypeScript. Here we want to say user, this is exactly this
part and insight want to merge our user identity
with property token. What I want to write here is user entity and
this is our class. And here we can write end. And here it is object. We stock in string. Why I'm writing like this. Because actually we want
to have new interface, but we don't want to specify
the inside all properties from user entity because
it doesn't make any sense, then it will be just a
duplicate from user entity. So actually we want to have all properties from user entity, but additionally token property. For this, we can use this end which actually merges two types. And this is why we're
merging our user entity with the object where inside
we have token stream. Now let's try to use this user response interface
inside our service. So here I am just
paste in that this is user response interface
and we need to import it. And as you can see, we're
getting directly and narrow. As you can see here, we have a property hash password is missing in type token
AD blah-blah-blah. We have all our properties. What is the hash password? If we will open here
our user entity. You can see on the bottom
before insert hash password, which actually means from our
user entity we're getting all properties and
hashed password also. But this is only the datatype, which actually means
we want to use our user entity but
result hashed password. And actually we can do this
by creating a new type, but just present
this hash password. For this, I will
jump back inside of a types and create
here user type. Here we can write user
dot type, dot ts. So here we want to export our new type and we'll
name it user type. What we want to do
here is just simply on meat from our user
entity one property. And for this n-type
script we have Omid. And inside we're passing
our user entity. There's a second
argument we're passing here string that
we want to emit. And this is our hash password, which actually means
our new user type is exactly user entity. So all properties but
except of hash password. Now we can use this user type inside our user
response interface. So we're just removing here user entity and right
in here user type. Now let's check if it's working. I am jumping back
inside or user service. And as you can see here, we don't get any errors. Because in our case
now we know that user response is
an interface where inside where merging
our user entity with object was talking. But actually from this
user entity inside user type were unmetered this hashed password,
this is it. And actually by using on
meat and then operator, you are using more
advanced TypeScript stuff. This is why if you really
know TypeScript good, you can write better nest
GIS applications also, let's check if we have any
errors inside of observer. As you can see now we
have the errors inside our user controller because here we didn't use the
correct interface. So let's check this out. Here. We're inside
user controller. Here we're returning back
the promise of user entity. And of course this is
not correct because our build user
service is returning for us user response interface, which means our
response for front-end. This is y here instead
of user entity, we must write user
response interface. And this is our interface from user entity was talking inside. Here we can of course
removed now user entity. Let's check this out. As you can see,
everything is green. Now we can open Postman
and try once again. As you can see, everything is working exactly like previously. But now we are on the safe side because we typed
everything correctly and actually capable use this response interfaces
everywhere in the next modules just to show what data where I've
been for the frontend.
17. Validation pipes: In this video, you will learn
how to validate requests in this chess and
actually nest Jess did a good job by
implementing the pipes. So what is pipes? The main idea that
we can somehow proceed with our arguments
inside controller. Normally inside
controller we have something from our
requests like for example, body, and we want to either
validated or transform it. We're doing this
through pipes and this is the standard
feature of nice chairs. And as you can see,
these are built in pipes like validation Pi
percent pipe and so on. And actually the
most popular from this list is a validation pipe. Because we can use
validation pipe together with our detours
that we made, for example, for registered request and out of the box in a
matter of seconds, we're getting really
nice validation. So let's try this out. Here we have our
create user request. What we can do after our posts, we can add one more decorator
and this called use pipes. Use pipes is common
from Nest chest. Now in size here we can say New and here we'll
validation pipe. As you can see, it
is already there and we don't need to do
anything at all. With this single liner. We're bringing the validation to our detail inside our method. And now of course it won't work. Let's see here, as you can see, we're getting the error. The class validated
package is missing. This is because this
functionality was by act in additional
NPM package, which means we're must
jump in the console. And right here you can add, and as you can see, the
name is class validated. So we can copy
this and end here. And class valid data is
coming also from less chairs. We just need to install it
and restart our web server. And here we must
get one more error because this one
package is not enough. As you can see here, we have one more error and in our
case glass transform. A package is missing. This is the second
package that we must install in order to
use validation pipes. Here I am writing the yarn ed, and here is our
class transformer. It is already installed. This is why we must
restart our webserver. And in this case it must work. As you can see, we don't have any errors now and
we're good to go. So actually how does
it work at Hope, the main idea is that
we're using detours. In our case here, we have a
create user detailed class. And this create user
DTO is exactly what is being checked inside
this new validation pipe. And actually in our case
now it doesn't check anything because here we
can jump inside our detail. Create user DTO, and we don't have any
validation rules here. So actually now we can add here validation rules
for our payload. First of all, we can say that user's name must be present. Here we can use
decorator is not empty. And as you can see that this
is outer input from class validated that we
installed previously. Now here we can add one more
rule is not empty because email also should not be
empty and also is e-mail. And as you can see, there
are a lot of stuff here, like it's enum is email
is empty and so on. So out of the box
we're getting a lot of staff for our validation rules. Here is password,
we can say here is not empty also because password is mandatory inside
our form of registration. What step do we need to
do in order to bring validation inside next chess? First of all, we're in style
and two additional packages. Secondly, we're using detours, which is just a class. Here we're using
class validate or decorators for every
property where we need to. Then we're just jumping inside our controller and we're using here use pipes were inside where providing validation pipe, which is the default pipe. Now let's check if we have any errors with don't have any. So let's jump inside of postman and check
if it's working. This is our normal
request where hidden sand and we're
creating the user. This is because in body
we're past all data. Now let's try and remove
everything from here. So we have just simply user here and we don't
have enough data. I'm hidden sand.
And as you can see, we're getting an amazing
validation errors just out of the box. So here we have status code 400, and here is our message. First of all, here
are messages for all our fields that they
should not be empty. We also have here that
email must be an email. And obviously now
it's not correct. And doing if we're
paste in everything but here we're just
missing password, then we will get the error
on further password, which actually means in
a matter of minutes, we configured our validation
for our registering request. Now, I want to
additionally to check if the e-mail and username
already exists. And actually it's not related to validation pipe settle because we can't really make a database requests
inside validation pipes, which actually means here inside controller book can't
validate create user DTO, and we must do it on the
level of user service. This is why here I
am jumping inside User Service and here is
our method create user. What we want now here is to
add some rules to check if this email is not used and
this username is also unique. And for this, we can
easily use our eardrum to check if we have the user
with such username and email. First of all, here I want
to write user by e-mail. And here we will use a weight. Here we have this
user repository and we have here a
method find one. You can understand
from the name. It finds the single
record by some predicate. Here we can pass an object and inside we can write e-mail. And here will be our create
user detour dot email. So here we will
get back a user if this email is already
registered inside our database. Now I want to do this
same for our username. Here we can name it
user Bye, username. Here we're using find one. Here we want username property. Here is create the
tour dot username. So actually here we're getting
a user or undefined it. And here also, now we can
write here the logic that if user by e-mail or
users by username. So if either of them is there, then we want to throw the
error that data are not valid. And actually in essence, this is the Mason that
you can throw error anywhere and it will be
propagated until the front-end, which means until our API. So what we want to do here
is to write thrown you. Here we can write
HTTP exception. And as you can see, this
is from Nest chest. And now inside we can write some message to
describe what happened. For example, here we can say
email or username. Taken. There's a second parameter
we want to write, what status code
we want to throw. And they really like photo too, because this is an
unprocessable entity. This means that the data of the user did not
pass our validation. And actually we don't
want to write here photo to like this because we have all these
status codes inside NYSE GS and they are
statically typed. Here I want to
write HTTP status, and as you can see,
it's from less chairs. And here we have
all the statuses and we can write here
unprocessable entity. And as you can see inside, we have four to two, which means that this
is an enum that we can use everywhere to throw
needed status code. Now let's check if it's working. Here. We don't have any errors. And let's try to create a user. I'm hitting here sand, and as you can see, we're
getting our new arrow, so it's not a validation
error here we have photo tool and here
is our message, email or username are taken. And this is because
every single time when we were registering
the user here we're using the same
credentials with full and full at gmail.com. And actually both of
them are already taken. And here of course, when we're checking this and this were getting back a record, which means we're
successfully validated that username or
email must be unique.
18. Login request: In this video, we will
implement login ID of the user. And actually here I want you to try and do it by yourself. And they have a full faith that you can do it on your own. Because actually now you have
enough knowledge to do it. And actually I have three
levels of complexity for you. First of all, is the difficult. Actually here is what
you must implement. As you can see in specification
for authentication, we have the URL slash, api slash users slash login. And this is our request, which actually looks exactly the same way
Register requests, but here we have only email
and password and username. As you can see, it
also returns a user, which means we have
exactly the same response like previously for
our registration. So you can reuse all
stuff that we prepared. If you think that you
can do it on your own, then I highly
recommend you to pause this video and try
to do it yourself. If you need a little
bit guidance from me. Here is level tool,
which is medium. Here is how I'm
planning to do this. First of all, as I said, we have a new request and it is related to the user
because this is the login, which means we can use exactly the same users
module and user controller. Here in CRT controller will
want to create a new request, which means we are creating
a new function login. And here we will use exactly
the same validation pipes. We will have a different URL, and here we'll also
need a detour. Here we have detour
for create user, but now we need to create a
new detour, which is login. User response will be the same
like and said registering. And here we will use
the new method that we must tried not create
user but login user. And actually now inside
service we must create a new function which
will login the user. The question is, what is login? Actually, we don't need
to implement login. We just need to return the user if we can find it by email. This is the basics. If you want to make
it more advanced, you can also implement
comparing the password. Because actually we want to compare the password that we are getting with the password
inside the database. For this, we can use a function
be gripped dot compare. Just to remind you, decrypt is the package that we used
to hash our password, which actually means
our login function simply gets the user
from the database. And if it is there, then checks the password
and returns the user. Here it is level two for you. If you think that you can
implement it on your own, then just pause the video
here and try it yourself. Now here is level easy. Let's just implement
it together. First of all, I want to jump
inside user controller. And as I said here, we must create a new function. And we can name
this function login because this is exactly
the login process. First of all, here the
question is what is login? And this is also post. And as you can see here,
we must provide a new URL, which is users slash login. This is exactly what
we can see here if we're finding login
inside our specification. The next part is to
create a function. And actually we can directly
write here use pipes. Because in any case, we just want to call this
validation pipe on our D2L. Here There's our
asynchronous function and we can name it login. Now inside this function, we must get the body. And actually as you saw here, the body is also
inside the user. So we can write
exactly the same code. Here is body user. And we know that
here we're getting our login details
of type detour. I will write here any we will
create detour in a second. Login details is
our argument and we want to specify what
we're getting back. Here. We're getting
the promise of our user response interface that we used inside registering. So actually as you can see, our code is super similar. Now inside this function, we want to get a user. So here we're using a weight
for this user service, and here will be our
new method login. And we're passing inside
our login details. Just to remind you of
this user is user entity, it's not user
response interface. This is why here we must use this user service and here build user response that
we prepared previously, because this function will automatically add
token to our response. Now let's create
our login duty on. For this, I will jump inside
D2L folder and name it here, Login User dot, dot ts. And actually we can copy, paste everything
from create user. But I will just once again, right from scratch so you
can see how it is written. Here we want our class and our classes login user detail on. And inside we have
only two fields. This is our email and password, and they both need
to be presented. This is y here we're
right in East, not empty. And here we have our password
field, which is redundant. This is why here we don't know
the password is a string. And now we need
to do the same is no temperature for our password. Here is read-only password
and this is a string. And actually as you can see, our detour is always
looking the same. You can write it
once and then either copy paste or use as an example. So our detail is created, we must use it inside
our controller. Here we have our login UTR, and this is login detour
that we just implemented. Now we just need to implement this login function
inside our service. But first of all, let's check if we implemented
everything successfully. I will comment out these
two lines and just return here login
for example, as any. And then right in here, just for the sake of testing, because if I unmute it, then we're getting the error
that we must return here, user response interface
and not a string. This is y, here is S any. And now we can console log here, our login duty to check if it is there, a
console logged it. Let's check if we
have any problems. As you can see here, after restarting, we
don't have any errors. Let's jump in Postman and
actually create the new route. Here we have slash users slash login will know that
this is posted and we must provide our email and password and we don't
need username here. And actually I want
to save this request. This is why here I am
clicking Save As here will be our login inside our
collection nets chairs. So now we can reduce
our login at anytime. Then hit in here send, as you can see, we are getting
back the message login. Now let's check what we
have inside console. As you can see, this
is our login detail. This is exactly
what we expected. Now everything is fine
and we just need to implement this login
method inside our service. So now I want to jump inside our user service and
create a new method here. Note that this will be
an asynchronous method because we will speak to our database. This
is why here it is. I sink login and we'll know that we're getting login
user detail on, which is of type login user TTR, backward getting
promise of user entity. And this is important
to remember, exactly like in our Create here, we're returning promise
of user entities, so we don't return
here some response for the front-end but
plain database data. This is why here we have
promise user entity. Now what we want
to do inside is to check if this user
exists with such e-mail. This is why here we
can say cones to use m. And here we're
using over eight. And exactly like we did
here to find the user, we can use find one with email. Actually, this is these
three lines here. What I can write is a weight, this user repository find one because we assumed that
we have only a single record, because we have a validation that our email is always unique. And now here inside
where write an email equals login user
dto dot e-mail. And actually here we got a user. This means at least
that user exists. And if not, then we must throw an error because the
credentials are not correct. This is where here I am writing. If not user, which means
user is not there, we want to throw our new era. And here we're using HTTP exception like we
already did previously. And here let's try it. For example, credentials
are not valid. Here we must provide
a status code. So here we have again HTTP status dot unprocessable entity, so four to two. Now, if you have
a user would want to check the password.
This is y here. What I can do is
have a comparison. So let's name this property
is password, correct. For this, we can use the
function compare and compare must be called with a weight because this is
an asynchronous function. Here I'm importing compare. This function is from decrypt. This, you can see I don't have autocomplete here
for some reason. This is why on the
top I will import this function compare
from decrypt. And just to remind you what
this function is doing, it compares the plane password
with our hashed version. We're using decrypt because
it is the easiest way to hash password and check
if the hair is exactly the same
light plain version. This is y here inside our login, we can write compare
and inside we must provide the password
and encrypted password. This is why here I have login
user detour dot password. This is our plane password. And then say user dot password, we have our hashed password. So actually here
we're getting true. Then this means that we
can authenticate the user. And if it is false, then we must throw an error. This is why here we
also want to throw an error if password is not
correct, this is why here, if password is not correct, we're throwing new era and this is of course,
HTTP exception. Here, for example, again, credentials are not valid. Here we have our HTTP status
dot and potential entity. And actually you
might ask why we did this if first
and then we have some logic and then
exactly the same if we could just write
it once and here, move this logic to the top. Yes, sure, you can do that. But actually the idea is that
if our user is not there, we don't need to execute
this code completely. This is why, First of all, I am checking for the user and secondly for correct
and password. Here we've drawn our error. Now we just need to return
our user from the database, which actually means that
login request simply returns the user that is founded in database if fall
validation is passed. Now let's check if it's working. Let's jump to our server. As you can see, no errors here. Let's jump and say Postman. And here I'm hitting sand. And as you can see, we're getting back all
this information. So user or our fields,
password and talking. And actually this is
almost good because here we have all fields
and also password. And of course don't want
to take our password from the database and send it to the front and because
it's not secure, but we will talk
about it in a second. As you can see, actually, we successfully implemented
our login because we did the check at the
password is there here. If I'm changing this password
on not correct version, then we are getting the message credentials are not valid, which means it is working. And actually we reuse a lot of code between our
registration and login. Because for example,
this generation of GBT talking we're using inside
build user response. And exactly built
user response is what prepares for us our
response for front-end. So now we just need to
solve the problem with this password that we're
getting back from our database. And actually this is really easy how we can do it
inside nice chairs. We can simply jump inside our user entity and
here is our password. And we can say
here, select false. What does it mean? It means that in all our requests by default, we're not selecting
the password. And actually if we want to select the password,
for example, for some check-in, then we
must say this explicitly. And let's check this out. Now, I'm hitting here sand. And as you can
see, we're getting 500 internal server error, which actually
means that our code is not working and we
have some problem. As you can see here, when I'm
jumping in our web server, we can see the error data and hash arguments are required. And actually this
error is with B crypt. Here we can jump
inside our service and we're using here be crypt
in Logan exactly here. What did the problem? Actually, the problem
is that we just said that we don't want
to select our password. This is why this password
is not inside our user. Let's console log
here, our user. You can see the
problem here that the user that we just
took from our database, and this is the
default find one. And actually the
default version, we'll just ignore
the selection of the password because we
defined it inside our entity. So let's jump on our server. We don't have any errors. Here. I'm hitting again.
And as you can see, we still get in 500. But here now we have the user. As you can see in
our user entity, we don't have a password, how we can fix it? Actually, the idea is that here, when we're selecting find one, we must get a user
with the password. Because if not, then
we can't compare it. But the main problem with that, we can't really say in find one that we want to select
additional password, we can only specify exactly the array of fields
that we want to select. So we're using here find one, this is fine, but here
as a second parameter, we must provide our options
here to the options select, and this is the array of
fields that we want to select. We really mass type
here, all our fields. And they know that this
is not that comfortable, but this is how it is
implemented inside type RM. And yes, there are
open issues that people want to make
it somehow better, but it's not there. But this is fine for us. We can type here a little
bit more and dried our list. Here we have AD
username, then email. After we need biography,
image, and password. Password is important here because only one we are
getting here the password, then we can make a comparison. Let's check this out. I am hitting sand once again, but as you can see here, we're getting password
exactly back. Why it is happening. Because here inside
our login with just using the same user like
here to do our check, which actually means we got the user and here we specified the password and we're
simply returning it here. And you might actually
say why we wrote this select false
here because it doesn't make any
sense in our case. Yes, in the case of Logan, it doesn't make that much sense, but it is super safe because we will reduce this
user entity a lot. For example, also for profiles, this is why we are
on the safe side. One by default, we
are not returning it. This means that we
can't really forget to exclude it because it's
not there by default. But what we can do
in our case now, here we're getting our check
with compare the user. And now what we can do here is simply delete the password. This is why here I will write
delete user dot password. And in this case, after this line, I will user
won't have password inside. And this is exactly the case only for logging in because most of the time we don't need the password inside our answers. Let's check if it's working. So I'm jumping inside
Postman hidden sand. And as you can see that
there is no password here, because after checking it
here is password correct. We'll remove the password
completely from our request. We've successfully implemented
our login request, and let's check once
again how it is working. First of all, here is
our validation pipes, which actually we didn't test. Let's test it now. I will remove here the password completely and just hit Send. And as you can see,
we are getting here validation pipes error, that password should
not be empty, which means everything
is working just fine. Now here we created
login duty also were getting it and
we're passing it inside. Our new method uses
service login. We have here build user response to back our user
identity correctly. Now inside this user service, we first of all
finding the user. But here we're selecting all our fields because
we must select password. Now explicitly, after this, Let's remove this console log. We're checking that
our user is there. And if it's not there,
we're throwing the error. Then we're checking here
our password from decrypt. And here we're checking if
password is not correct, we're throwing the error again. And now at the end version
moving password because we don't need this anymore
and return in the user. If you tried to make
login feature on your own and you did it even partial,
then you're awesome. And it is really important for your
knowledge of nice chairs.
19. Auth middleware: In this video, we will learn such important point from
ness chairs as middlewares. This is because now we must
implement working with token. As you saw in the
previous video, after we're making
login or registering, we're getting back this token. So the idea is that front
and we'll get this token, store it in local
storage or cookie, and attach it to every request. Which actually means
then backend can know what requests to what
user is belonging. And this is exactly
what we want. So actually when we're making
some request, for example, getting currentUser,
then we will get this token inside
headers. This is y. Let's implement getting of current user and parcel of
the token from headers. As you can see here, we have the request
get current user, which is slushy pie slash user. Here we see that
authentication is required. This is the part
for other video. It doesn't have anything to
do with our middlewares. But here this request must
return our user back. What is the idea? Here inside our
users Controller? Work creating new request. And as you can see this
a slash api slash user. And it will be a GET request. But appointed that
we don't have here any body or something that
we're passing inside request. We're getting through headers
magically, our token, and we will parse it before we will get to our request here. The main point is that we
want to get currentUser from this header every single time before were
hidden controller. Why? Because it is more
comfortable for us. We can just say, okay, we have our
request, for example, login, and we know that
if this was attached, then we also get this current user already
here inside request, which actually means we
should not every single time in every controller,
in every action, right, request headers
take from their token, parse this token, then
get user from database. By this token, we will
all do this before. And as you already know this use pipes are for
our parameters here. So actually we're
doing something with parameters before were hidden. Our action inside
controller and middlewares is a little bit similar. We're not working with parameters but with
request itself. So middleware is happening before our request
hits our controller. This is why it is middleware. It's in the middle. This is why we will
create a middleware for our authentication where
inside verbal bars our token. But as the first step, we must first create
here a new function. So here I'm creating
gatt and we'll know the tau URL is just use it because it stays
here in our spec. Here is our GET request
and here we need a sink and let's name
it current user. Because this is
the request to get the current user
normally in front. And we're making this
request every single time when we initialize
our front end application. Here, we're not getting
any parameter here. And we just return here promise of our user
response interface. Because as you can
see here in spec, it returns our user. Just to remind you, our user is this strange notation
with property users. So we need also to build
the correct response. This is why this
function that we created earlier will be quite
handy for us here. For now, let's just
return inside, for example, current user. So we can see that this is
working and of course as any, because in this case we
are saying that this is a promise and this is
exactly not a promise. This is just a plain data, but we will change
it in a second. Now we must input this get
decorator, it's not there. And we also want here to
get access to our request. Why? Because they actually
nest chairs is a wrapper around express the request, which is the whole request. We're inside, we have
some data, for example, our headers, or later our user. And as you can see here that the example from documentation, and we can use the
decorator request to get the whole request
that we're making. Here we got only body but request will return
us the whole request. This is where here I am saying
request and we know that this is a decorator and
here we must adjust, create a local property
request of type request. Now let's console
log what is request. So here is our request. Now we must do this
request inside postman. As you can see here,
we have some error. Request is not defined. So actually this request is coming from
expressed directly. This is why I'm importing
here request from expressed, not express, serve static core. Of course my
autocomplete was not good, but express itself. And as you can see, we
don't need to install additional express because
it is already inside an SDS. Now let's check if it's working. As you can see, no errors here. Let's jump inside
Postman and we want to make a get request
for slash user. And now let's hit Send. And as you can see, we're
getting back currentUser, which means we successfully
implemented our action. And now I want to save this
request here where hidden, Save As this is the
request for current user. And we're safe in it inside
next year's collection. So here it is. Now every single time we can hit send and we're
getting our request. Now let's look inside console, and as you can see
here is a lot of logs, and this is actually
our full request. And as you can see that there's
lots of information here. And everything we can read for us is interesting,
is header spot. As you can see, these are all headers that we are getting. So normally our
flow is like this. So we're jumping in
and said Postman, let's say that we're in
our front end application. We're making here our login with our body and where hidden sand. And we're getting back the stock in front and save
this token somewhere, and then flaunt and later makes this current user request. And it must attach inside
headers new property. This is why here I am hidden
on Header and here we can provide and you keep though Q will be named authorization. And here the value will be
token space and our token. And now I can hit send. And let's check what we have. And if you are asking
why I wrote like this, because in our
specification here is information regarding
authentication header. So actually if our
request is authenticated, we can provide here
authorization header and it should look like token
space and are talking here. And this is exactly
what we did here. So token space and our token. Now if we will jump inside our web server here is our log. Somewhere here we
have a new header. So actually if we
find it on the top, you can see that here we have
our authorization header, and this is our header, which means actually we can
inside our controller here, somehow bars this header, get authorization token from it, then get current user, and then return this current
user or operate with it. But of course, we don't want to do this for every request. This is why we will
create a middleware. Now, what did they did? Actually, the idea is
that our middleware will just take this header
before our request will hit controller and
from this token and get current hearsay and
attach it to our request, which actually means here
in set current user, we can get our
user directly from the request without
bothering restocking. So now let's create
our middleware. For this insource user, I will create a new folder
which is called middlewares. Because actually we are creating the middleware which
belongs to the user, because it's related to
authentications users and so on. The inside we want to create new file aus dot
middleware, dot ts. And in this case,
middleware is our entity. And what is Middleware? It is actually a
class and this is y. Here will be expert
class, our middleware. And the most important is
this implements too because we must implement something that nest chest wants from us. This is why here we're
saying nest middleware. This you can see
after outer input, we're getting here and narrow. So property use is missing in type of middleware,
bot is required. This is exactly the point. So our middleware must provide a function use because
inside this US, we can do something
regarding our request. This is why here I will
create the function use. Here we're getting a
request response and next. And actually the idea
is that we can read all these things here
and then do next. And next means that we did
everything that we wanted and want to continue with pass in our request
to the controller. This is why here I will
write out middleware. And actually we're interested
only in request headers. And now here we must call next, just like this to say that we're finished
with our middleware. So actually this is the basic middleware which
doesn't do anything. So our middleware is there. Now we're must registered
inside some module. And actually weekend registered for example, in user module. But actually I want to
register it inside app module because we want for all our requests all
across the application, always decode our token
and get current user. This will be easier for
us and then we don't need to write additional
logic in some requests. And here is how we can provide globally for all our actions. This middleware inside class at module we must
write here, configure. This is a function
where inside we have consumer and this is
middleware consumer. I will open this
function and inside we want to write consumer apply. Here we're biasing
our OS middleware that we just created. Now here we can say
for routes and specify here for what routes we want
to apply this middleware. And actually we want to
do it for all routes. This is why here
the path is Start. And method will be
request method dot o, which actually means
to all methods. You don't really need to
learn this code by heart, you can always find this
example in the documentation. The most important
point is that you understand that if you want to apply globalism middleware or not even globally inside module, you are right in this
configured parent inside consumer apply. Here is your middleware. And you can say for what route you want to
apply your middleware. In our case, it is a
global middleware. This is why we're applying
it here inside at module. Now let's check if it's working. Where jumping here
inside the console, we don't have any errors. And now what I want to do is first of all
remove console log from user controller because it's too much to
see in the console. Now let's check if it's working. So I'm jumping in postmen here, don't forget inside headers we must provide the
token which is valid. I'm hitting sand. And now let's check what
we have inside console. As you can see here, that
the console of middle, this is exactly console
log from our middleware. And as you can see here, we're getting exactly
the whole request. And we're interested in
this authorization token, which actually means our
middleware that we've just created is happening
before our controller. Now we can do something with
the request and then hit Next and then provide updated request inside
our controller. Here is one important point. We really want separation of concerns inside of middlewares. We can also throw errors. For example, here,
if user is not logged in weekend,
throw something here. But I want to separate
the logic because we don't want in our
middleware to throw something. We just want to decode our user. And if you don't have a
geosphere or a header, then we don't do anything and then request that user
simply will be now, but we don't want to
throw anything here. This is super important
because we're attaching this OS middleware
to all our requests. Which means if we are
throwing something here, then it will be for
all our requests. And we don't want this. First of all here,
I want to write datatypes and actually
request is of type, request and response
is of type response. And here next is of type. Next function. We need additionally to add
here request and response. Now we need to write some logic to check if
we have head or not. This is why here we can
write if and here will be request dot headers,
dot authorization. So actually we're checking if
we don't have this request. Then here we're setting
the request user to now, and we're just calling Next. And here we also want a return just to be
on the safe side, but I think nest is enough and we don't
need to return it here, but it won't do any harm, so I will leave it here. The idea is that in this IV, if we don't have a header, we're just saying
in requestUser that our user is now and we
don't do anything at all. But here is one problem. As you can see here, property user does not
exist on type request. This is actually correct because request comes from Express and we want somehow correctly to
set a user inside requests. And for this, we can extend the standard request
of expressing. This is why I want to jump in source and create a
new folder types. Because here I want to create a global type where we
will extend our request. And here I want to create
Express request interface Ts. Now inside I want to export new interface and this
is express request. Here I'm saying extends request. So actually this request
is coming from express. This is y here I'm importing
my request from express. Now inside this interface, what I want to do is add the user and this user
can be there or not. This is why Here
is question mark. Here I want user entity. User entity is our user result token without any
additional properties or transformations. This is exactly what we want to use now inside our middleware. So let's jump back inside our user middlewares
out middleware. And here instead of request, I will drive our
Express request. This is the updated version. Sure, we could write any, for example, but it's
not the best approach. The best approach is
to extend the request. And now as you can see, we
don't have an error because here we're saying that
user can be not there. The next step is to get a token. So here we can say that
we want to get a token, want to split our string, because we know that
they have inside the word token and our token. This is why here we can
try to request headers, and here we have authorization. And we want to split it by space because we
have only two words. And we want to take the second argument
here from our array. And let's console
log here token, so we can check if
everything is working. Let's save this and
look in our web server. As you can see, no errors here. Let's jump inside
Postman and hit Send. Now let's see here as you can
see that this is our token, which actually means
we successfully got talking here
from our headers. Our next step is by this
token to find a user. But first of all,
we're master the code token to get some
information from it. And we must always wrap our
decoding of the token in try-catch because
PivotTable throw a scenario if the
token is not valid, this is way here I am
writing try-catch. And actually if we have a cache and if we
have here an arrow, we want to return
here the same code like here on the top
request user now, because if we can't parse token, it means that user is not there. Requested user equals. Now, here I want to call next. This is our cage. Now instead, try ****, want to decode our token. So here we have decoded. Here we must call a function
verify from JSON web token. So let's import here on the top, verify from JSON Web Token. Here we can now write
verify and inside we want to pass our token that
we got and our secret. And just to remind you here
inside our use of service, we have the code generated DVT, and to generate this GBT
will use GET secret. Now to decode it on backend, we always need to use
distributed secret. This is why here I am
biasing our GET secret. Now let's check what we are getting back inside
our console log. So here we have a decode. And they also want
here to write next, because in other case, book bond get inside our
controller without this next. As you can see, no errors here. Let's hit inside Postman sand. And as you can see, we're
getting the error cannot get user when you are
getting something like this, probably to have
some error inside middleware so you're not
hitting the controller. So let's jump in set console. As you can see, we
have here stack trace, but for us it's the most
important here is the code. So actually we
successfully decoded our token and we have
inside ID of the user, username and email,
which means we can now use this decoding information
to work with our user. So the next step
here will be to use the code information and to
get user from the database. But the problem is that here
we don't have access to user repository and they really don't want
to inject it here. What we can do is use
here user service. What I want to do now is jump inside User Service and create here a new method which
will get used by AD. Here I want to create a
sync and let's name it, for example, get or find by ID. And we're passing inside
AD, which is a number. Now we want back a
promise of user entity. And now inside we simply need to return this user repository. Here we can use find one
and pass inside our AD. So actually this is
just a single line. This is just a wrapper sober avoid using repository
inside middleware, but we're using our service. Now we can use this find by
80 inside our middlewares. We can easily inject it here because this is just a class. This is why here we have a constructor here exactly
like in the controller. I'm saying private read-only. Here will be our user service of type user service where
we wrote our method. Now we can use this user service here to get the user
from the database. Here we can remove console
log and dry it user where we're calling await because this is the
request to the database. And here will be this
user service not used but user service dot. And here is our find by ID and inside we're passing
decode dot AD. So actually this line will find the user by the CD from
the token inside database. And we can simply say here, request user equals our user. Now let's check if it's working. So I'm jumping here, we don't have any errors. Now let's jump inside
Postman and hit Send. As you can see,
we're still getting the error, unhandled
promised rejection. And actually we can debug
this code really long time. But the actual problem
is here that I forgot to write on the
top injectable decorator. Problem with injectable is that you are getting
some other errors, but not directly that you
forgot to write an injectable. This is why it is super
difficult to fix. This is why I highly
recommend you to always pay attention if you rolled injectable
for your services or middlewares or not. Now let's check if it's working. So let's jump here. As you can see, we're
still getting the error. But now this is the other arrow. We have here the error that nest countries of dependencies
of the mouth middleware. And we must make sure that user service is available
for app module. And the messages here are
super important for us. These are potential solutions. First of all, use a service must be a provider of app module, but we don't want
this because uses service belongs
to our OS module. This is where hear that
the second solution, if user service is export it
from the separate module, is this module imported
inside app module? So let's check this. If I'm jumping inside
our app module, you can see that here we're
importing our user module. This is fine. This is exactly what we want. The problem is that
inside user module, we didn't expert user service. This is why we can't use, uses service outside
of our user module. And we want to use it because we registered our middleware
inside a module. This is where here we
must provide inside experts, our user service. In this case, it will
be available outside. Now actually, I solve one more problem
inside our middleware. So let's jump
inside middlewares. As you can see here
on the bottom, we're calling next once again, this is not correct because
we don't want and here we have already done next for our if condition and return. And here we have next
for our try-catch, which means here we have additional Next and
we probably will get some errors because we're calling next more than one time. So let's jump here
inside web server, but don't have any errors. Let's jump inside
Postman and hit Send. Now we're not
getting any errors, but we are getting current user. So first of all, I want here to remove the console log
from our middleware. And actually, as you can see, we're not using here response. This is why here we
can write underscore to say that this is an
induced variable for us. Now let's jump inside
our user controller. And what we want to do
here is console log, our request dot user here will be current user in controller. Here we want to read
our request dot user. And as you can see here, we're getting exactly
the same error because it's not
request anymore, but express request that
were created and extended. Now we don't have an error because here we
have a user inside. Here we don't have any errors. Let's jump to Postman hit Send. Now check in console. As you can see, this
is our user entity that we successfully got
inside our middleware. This is our user that we fetched by talking
inside middleware. And now we can use it directly inside our current user request. Which actually means now
every single time when inside some action of the controller will
need current user, we can get it directly from the request user was
out parsing the token. Which means we really
did all heavy lifting of working with stalking
inside the middle there. Now as we have our
currentUser in requestUser, we can just return the data
in the correct format here. This is why I will return here, this dot user service, and here is build user response. And we're passing
inside our request dot USA because we know that
this is our current user. Let's check if it's working. I am jumping inside
postmen, hidden sand. And this is our normal
user like we wanted. So we have here our
token, all these fields. And this is actually the get of the current user
that we implemented.
20. User decorator: In this video, I want to talk about decorators
inside nice chairs. We already saw a lot of them. As you can see, I'm on
the official website of chess and here our
program decorator. So these are the curators regarding programs
inside controllers. As you can see here, we have requests or wreck
were already used this we can also use response
next session per gram, body, body world rarely used, and so on and so on. As you can see, there are
lots of the curators and we can easily use them
and we already did that, but we can also create
our own decorators. In this video, I want to
create one more decorator, which will be our own
custom decorator. As you can see in
any of our request, because we created
the middleware, we can get current user. And to do this, we
are writing here request decorator to
get the whole request. And then we're using
the request dot user. This is completely fine. We can live with it, but we can of course do better. We can write a custom
decorator to get here directly a user and
not the request. Let's build this now. For this, I want
inside User folder to create a new folder which
is called decorators. And here inside we will store all our decorators which are
related to use a module. What I want to do here is to
create a new decorator user, dot decorator, dot ds. And as you can see here, decorator is our entity. And actually decorator is really different from other
entities, for example, like middlewares or services, because we don't need to
register it inside next chess. Here we simply create it like
just calling a function. This is y. Here I am write an export const and we want to create
a decorator user, because this will
be the decorator to get user from our request. Here book wants to call
create, but RAM decorator. And as you can see,
this is a function from less chairs to create
a parameter decorator. This means that our decorator will be used only with params. Now inside our Create
Parameter decorator, we must provide the function. This function has
two properties. First of all, it is data
and I will write here any, and they will say
why in a second. And here we have our context, and it will be our
execution contexts. Now here we have a function and here we can return
whatever we want. So we can write here four. As you can see here, to create a decorator, we're using create
program decorator. And inside we're passing
function and we have access to two arguments and we will talk about
them in a second. So the idea of creating pattern decorator is
just to return a value. This is where here we're
simply return in full. Now let's try to use it. We didn't write any logic now, we just want to bind it. This is why I will jump
inside our controller. And here on the bottom
where we have our request. We can additionally
to our request, use also other decorator
which is called user. Here inside were not
provided anything. And here I will say user any because we didn't even specify
what we're getting back. And now we need to
import this user. So as you can see on the top, we're importing our user from
decorators, user decorator. So this means that now we just created a decorator
and passed it here. What I want to do now is
write console log user, and here will be our
user from the decorator. Now let's check what
value do we get? As you can see here, we
don't have any errors. Let's jump inside. Postmen hit Send. As you can see, everything
is working, no changes here. But now in the console
you can see user foo, which means we got a
value from our decorator. So actually all
params decorators and our custom one also, I get an access to the full request and can get
some information from there. Which actually means
decorator is simply a sugar to work
comfortably with request. Now let's jump back inside our decorator and
dried better logic. First of all, the question
why I wrote here data and if we will open here
on the right controller, we can provide inside the user decorator some
stream, for example, AD. And actually the idea is that here we can get back
the whole user. So this is current user. Or we can get specifically
only a single value. For example, the
AD of this user, which actually means that data can be undefined it if we don't provide something or it can be some value to get from the user. The next question
is, what is context? And actually contexts is
an execution context. You can see it from datatype. The main point is that
from execution contexts, we can get, for
example, our request. Here we can write that
we have a request. This is our contexts dot here we need to write
switch to HTTP. And then dot GET request. This you saw there were also functions to get
response get next, which actually means
work by flexible here. Now we can do something whatever we want
with this request. And actually what we want
to do, we can say here, if our request user
does not exist, then we want to return here. Now, in this case
inside our decorator, we simply get now if we
don't have any token over, didn't get the user
inside middleware. Now, after this, we can
write if we have data, and this means that we specified some property to get it
nested from our current user. Then here we want to return
request dot USA data, for example, data is AD. Then here we will return
a request user ID. And last but not least here
we can return the full user. So here will be
request dot user, and we don't need
this return full. So actually, as you can see, decorators are
just sugar for us. We don't want to write all this logic every single
time in such controller. This is why we're moving all this logic
inside the crater. Here we simply return null
or we select some data, or we return our user. Let's check how it works. So here we're jumping back
inside or user controller. And as you can see
here, I have user. Let's check if it's working. I am running the request inside. Postmen were checking the
console and as you can see, regard our user
entity from our user. And actually now
here we can say that this is our user entity because we're sure that here we will get Houston and they know
what you want to say. Now, it is not clear
that we will get here. Always say user, because I wrote inside the decorator that
we can get here now, and you are totally correct. This is why in the next video, we will talk about gourds. We will make our controller
so that here we can't really get now and
we can get on user. But this is the topic
for another video. So for us it's
important that we can write here user, user identity. And instead of request user
right here, just user. Now we can reuse our decorator everywhere to get
a current user. We can also write here ID just to get on with
the ID of the user. So here let's check this. We're starting here,
our web server. We're jumping to the postmen. We're not getting all fields
because we didn't provide correct information
inside service because they got just an AD. As you can see here, user1, where getting here only
the number which is NAD, which actually means that
we can read directly just a single property if we want to offer our currentUser. But in our case here, of course, we don't need to provide
anything and we're must pass our user inside here. Also, we can remove here request because
we're not using it anymore and we simply
use our user decorator.
21. Auth guard: In one of previous videos, we'll learn about middlewares. They said that there we can do whatever born with requests, and we actually can
throw some errors. For example, when a
user is not logged in, just to remind you, here is the code of our OS middleware. Actually here we're
not throwing anything. If we don't have current user, we simply set it as a. Now, this is completely
correct because we're using this middleware everywhere
on every single route. But sometimes we want
to throw an error. For example, here, when we're talking about our
user controller, we have here get current user. And normally if you
don't have token, we want to throw an error
for 01 Unauthorized. The question is where we
want to pack this logic. And the next years we have amazing thing which
is called words. As you can see here, we just need this picture. So we have client-side like
front-end, then we're here, we should appear request
and then we have word before it hits
our route handler. You might task,
What's the difference then between middleware
and weren't? Actually the point of word
is simpler to create, can activate function,
and nothing more. Middleware is much more flexible because you can do
whatever you want there. You can use
middlewares as quartz. But I highly recommend
you to put the logic regarding roles or
access inside girls, because this is exactly
the purpose of squares. In this video, we want
to create our R-squared, the pointed that we
can use it only in the places where we really
want to throw the error. For example, here in this
request get current user. We really want to
throw an error if our user in this request
is not logged in. Just to remind you, we have middleware in
every single request. Which means the only
thing that we want to do inside world is check if we have a user inside the request because gouache will be
called after middleware. If we don't have a user, then we're throwing the error. Let's do this now. For this inside source users, we can create a new folder
and call it gourds. And here we will have all our boards which are
related to our user module. Let's create here
our word dot ds. So the idea of this
is just to throw 401 when the user
is not authorized. Here we want to expert class, and here we have our word. And here we have implements
of can activate. This, you can see can activate
is coming from Nest chess. And here we're getting that
we didn't implement it correctly because we must
create, can activate function. And this is exactly
the goal of our Lord. And of course here we
should not forget our injectable or we will
have magic errors. This is why here I am adding it. And now we must create here
our can activate function. So here I am writing
can activate. And as you can see, we're
getting context again. We're already
worked with context inside our params decorators. So actually this context
is exactly the same. This is our execution context. Now back we're getting Boolean because
connective eight regions, either true or false, and false means that we
don't have any access. First of all, here
we want to get our request just like
we did previously. So here is our request, and here we have contexts, then switch to HTTP. And here we have GET request. But the problem is here that
GET request will return the request of the Express and we want our updated request. So here we need to provide a correct datatype and we can provide here are
express request. In this case inside request
we will have our user. Now here we can write
if request dot user, so we have a user, then we're returning
here through this, you can see we don't need to do anything with
requests because we already have used inside because middlewares I have been
in before our can quiet. Now, if we don't have user
would want to throw an arrow. Here will be thrown
new HTTP exception. And inside we're
passing our message, for example, not authorized. And as the second
parameter, of course, our status code here will be http status dot on the thrust. And unauthorized is 401, which is exactly what we wanted. And actually we're already implemented the
whole world fast. This quite checks if we
have user inside request. If we have it, then
we're returning true. If not, we get an error. Now, we must registered
inside every module, where inside controller we
want to use this squared. This is y here we must registered
inside our user module. So here inside providers, I am right in our world. Now, we just need to use
it inside our controller. So let's jump back in. User controller here
is our get and we can write here and you
decorator use gourds. And inside we must
provide our outward. This is y here I'm simply write an outward without
round brackets, just like class, and
then just save it. And as you can see on the top, I have input from USC words
and import of my outward. This is exactly the
line how we can add our guards to this route. In this case, first
of all happens middleware to get current
user from the token. Then we have here u squared and this u squared inside
will either return true, so we're coming here, or we simply throw an error. Let's check if it's working. I'm jumping in our web server would don't have any errors. Now let's try our postman. I'm hidden sand,
and as you can see, we're getting back our
request as normal, which means we're past our GE worth and everything is fine. But if I will break this token, for example here I can remove token completely hidden sand, as you can see where getting
status for 01 unauthorized. This is exactly correct
because we're born for our request to return 401 if we're not log-in
because we don't have token sober control the
return current user data. As you can see inside NESDIS, we have a lot of different
entities that are already prepared for us and we can
just tune them a little bit. Then our code is really super easy to support
and understand. As you can see in a
matter of seconds, we can first of all protect
our route and not only here, but in every place
of our application. And then if we have our user, we can use it and get it
with our decorator user.
22. Updating current user: In this video, we will implement the last method of
our user module, and this is updating
of our currentUser. Let's have a look here. We have our spec update USA and our request is
slash api slash user. This is put because
we're updating it. And here is our request. Actually inside we
have a property user. As always, here are only three
fields that we can update. Email, biography, and image. As you can see,
authentication is required and we're
returning back user. And I think that this is a nice small feature
that you can try and implement on your own. And as always, we
have three levels. First of all, is hard
if you just want to try it by yourself without
my help or guidance, just pause this
video and try it. Now, the second level is medium. So here are some of my advice is actually
what do we need here? We will create inside
our controller, new method was put to
update our current user. The most important part here is the line authentication
required. This actually means
that we can simply use your squareds outward because this is the word for our authentication and visit. We really know that only authenticated people
can come to our request. Secondly, verb date in
here, current user, which actually means
we don't need to get a user from the
database because we're already getting it through this user decorator like we
did previously inside get. But of course we must
create a new method inside those service where we
will update our user. And last but not least, we must create a
new DTO for update. Already created a detail
or four create user. And here for update
we have another D2L. If you want to try and create
this feature on your own, then pause this video now. And here is the easiest level. We will just create it together. First of all, let's start
with creating our DTL. This is why I will jump
in user slaves DTO. And here we have our
create user detail. In this case, you
can actually copy paste almost all fields on our new update user detour because it will look
exactly the same. And actually I will copy paste everything because I don't
want to type it again. We're already did that. You already saw how
we're creating it. So our idea that here I have expert class and here is
update user determine. The question is, what
fields do we meet here? First of all, is of
course, username, email, password,
password we don't need. And here we also need read-only
filled for biography. And this is a string. And last but not least
is of course, image. But here is an important point. As you can see here,
accepted fields are e-mail, username, password,
image, and biography. But they're actually
not required. And it doesn't say here that
we have any validation. Here we don't need
any checks for is not empty because we won't
validate our detail. Here. We simply have our update user details with
these four fields which are specified here. And they actually,
as you can see here, we don't have a username, but in all APIs that
I saw previously, username is also implemented. For example, here in
Angular railroad diode. This is my settings. This is exactly the update
of my current user. Actually this second
field use the username. Here. Obviously I can
update my username. Passwords should not be blank. We must provide the
correct password. This is how it works
on the real front-end. Now, let's create our
controller method. This is why I will jump
in our user controller. And here on the bottom group
wanted to create new method. And we'll know
that this is a put and this is a route
for slash user. This is why here we
have slash user. And now we want to use here our required for authorized access. So here we're just providing our GVD and we're good to go. Now here we have our
method and we can name it, for example, update or
update current user. I really like longer
names because it brings you some understanding
because we will update. It's not clear what
we're updating. Here inside. We're
getting two things. First of all, we want to
get our decorator user. This is to get our current user. And here we have our user, which is our user entity. So this is the first
parameter that we need. The second parameter
is our form, which means detour, which means this stuff that we will
send inside the request. Here we want to say that we want body and from the body would want to read our user and would did exactly
this here on the top. For example, when we created
user and here we have create user detail here inside
body where bison, that this is update
user details. Of type update user detail
that we just created. And we know that
bank who wanted to get our normal user response. This is why here I am writing this promise of user
response interface. Let's close that
for now and save. As you can see, we don't have any errors except all of that. We don't have any body
here inside our function. Now, the question is what
we will implement here? And actually the idea is exactly the same
like with grade. We're calling update, update
returns for us a user. And then we want with
the help of build user response to get
the correct response. Which means here is our user. And we have a method way
to this user service. We will create a
22nd and inside, for example, update user. And actually as
you can see here, my method is called not update current user
but update user. Which means we can prepare this method is really reusable. We can update any user opposite, and it actually makes sense. But this means that we don't
need the full user here, but just NAD, because here
we are getting our AD, for example, current user ID. And we know that
this is a number. Now inside here whereby sin ID and our
update user do turn. In this case, we're building our function not just
for current user, but for any user
that we want to. We can update any user by
this CD and these details. Now after this,
we of course want to return our user service dot built user response and
we're biasing inside our AD. So as you can see,
our code inside every single action is
looking really similar. Now we just need to create
this additional method update user inside our service. So let's jump here
in User Service. For example, here
somewhere on the bottom. For example, before
generativity, we can create new
method update user will know that
here we're getting user ID number and here will be our update user
details of type, update, user duty on back, we're getting our
promise of user entity. And our user entity is
the same user as always. Now what we want to do
inside is first of all, find the user by d and secondly, updated with our user detail. Here we can write
that we need to use and we can call
here a weight, but we're already created
method find by ID. So we actually can
use this method or directly this user
repository find one. It doesn't make any difference. But if we already created
the method, let's use it. This is why this find by ID. And inside we're
biasing our user AD. This line will return as a user, but actually of course
we need to write here, I think in other
case, it won't work. Now we've got our user, and here we want to
overwrite properties of this user with our
update user detail. For this, we can use object
assign. Here we're passing. First of all, our
target will be user and our source will be
update user detail. Because first of all, is the object wherever we
want to update the fields. And secondly, what fields
were born to update. This mutates our user. So we're not creating
the UE user, but we're mutating this object. Now, the only thing that we must do is to save our user again. Here we are updated all fields, and now we can save this
user and return it back. This is y, here is a weight,
this user repository, and here we have dot save
wherever biasing our user. And actually this safe, we will update our user. And for this we of course
must have inside ID. As you can see, we implemented our whole update user method
in stream lines of code, which actually means
type eardrum is super strong together
with Nest years. Now let's check if
it's all working. As you can see
here, we're getting some errors inside
user controller, can't find name ID. Let's jump here in our
controller on 57th line, and here is of course not ID, but current user ID. So this is the correct name. Now we don't have any
errors here actually, we must import put on the
top who didn't do it before. Let's jump now here as you
can see, everything is green. Now let's create a new method. So actually here we already
have three of them. Now we want to make a
put for our user and we must provide here a token because in other cases
were born bit logged in. Now we must also provide a body, because in body, we're providing what we
want to overwrite. For example, let's override
here a field biography. This is why I'm providing
here biography. This is my biography. And I'm hitting sand here. And as you can see, if we got
back our new updated user, we got all information like your should be also restocking, which is important for us. And here inside biography, we're getting this
updated biography, which means our code
is working correctly. And in thrill lines, we implemented on
your service method where we can update
any user that we want. And actually this we're
all methods that we must implement inside
our user module.
23. Creating article module: In this video, we will
start a new section of our project because we fully finished our
authentication module. Don't use section is article. Actually we have a lot of
stuff to do regarding article. We can create article
update, article, delete article, like
dislike articles and so on. So there is a lot of
stuff to implement. But in this video, we'll need to create our basic molecule and
service for our new module. This is y. Let's jump inside our
editor and create here in source new folder where we
will store our article. Here is our folder article, this is our new module and all logic regarding our article, we will pack here. First of all, we
must create article module.js if you don't remember
how to create modules. So controllers, you can look in our old code or for
example, user or 10. First of all, here we must
expert our new class. This is article module. Here on the top we need
our module, sorry, not in g, But just a
module here inside. We must provide our
controller later. But for now we can simply say that we don't have
any controllers. The next step is to register our article module
inside app module. This is why we're jumping inside app module and here
inside in birds, where input in our
new article module. And don't forget to
import it on the top. So our module is there. Now we need to create
a new controller. Here let's create a new file, article dot controller dot ds, where we will have all our
actions regarding our article. So let's jump here
and we want here to expert article controller. On the top, we want here
a decorator controller. The most important for us that all our requests with political, our starting with the word
article here in our schema, we can check how it looks like. So here is a single article. As you can see, we have
lots of fields and all these fields we must
implement inside our entity. Here we have a lot
of APIs like slash, api slash articles
to get a list. And as you can see here, we have a lot of
query parameters. Then we can get a feed
of the article as single article with the
slug create article. But the most
important for us that always we have this
prefix of articles. This is why we can set
it once here inside controller and NADH
inside every action. Now let's add this controller
inside our module. Here, insert controllers, we must register our
article controller. Controller is there. Let's create at
least one action. We want to implement it just to test that
everything is working. What I want to create
here first use, of course, creating
of the article. Here we can say
that this will be post request because
this is the Create. And here we will
have a cin grade. We won't try it any
parameters here or what we're getting back here, I will simply return
create article. In this case, we can check
the tau code is working. And of course we must
import here our post. So let's check, first of all, in web that everything
is working. And actually here we must
seal logs for our new route. And as you can see here, we have an article controller and
mapped slash article post, which actually means
everything is working. But let's test this for this, I will champion set postmen. Here we have a new URL, so it will be articles URL
and it will be post request here I want to save it and the name will be create article. And it will be in our
collection as chess. Let's save this. Now we have District west, this is opposed, and
here is our body. And actually if we check here, as you can see, for example, for create will always pack all our data inside the
additional article property, exactly how we did
previously with user. So here we will have our
article and here we can pass whatever because for
now we just wanted to check that our
controller is working. As you can see here, we're
getting back great article, which means everything is
buying this successfully. Now, I also want to
create a service, because for sure we must create a service for article
in the same way how we did for user to write all our business logic
inside the service. This is where here I will
create our article services.js. So let's jump inside
and here we want to export our new class
article service. Don't forget that we must write our injectable decorator
here on the top. In other case,
nothing will work. What we can create here
is our new method. We can name it creates
article won't implement it, but just return some
string just for testing. Here I want to return create
article from service. Now we can register this service and use it
inside our controller. First of all, inside
our article module, here we're masked inside providers use our
articles service. So here is our service. Now let's use it inside
article controller. For this, we must provide
here a constructor, and here we have our private
read-only article service. This is of type article service. Now instead of this great
article we can use here, this dot article
service create article. Now let's check if it's working. We don't have any errors here. Let's jump inside
Postman and hit Send. As you can see, we
are getting message create the article from service, which means we'll configure
service correctly. Now, we must create an
entity for the article. And as you can see, this is how our normal article
is looking like. So we have lots of
fields here like slug, title, description and so
on, and even relations. But we will talk about
relations later. For now, we will create all these fields except
of favorited and awesome. For this, let's
create a new file, article dot and dot ds. And just to remind you, we need to export here
our article entity. And on the top we must say
that this is an entity. Here we're providing additional
name for our table name. And here we want to have
not article but articles. Now inside we can
create all our columns. And of course we're
starting with AD. This is y here, there is
primary generated column, and this is a DIY
of type number. Now the next one will
be our first column, which will be slung. The second will be
one more column, and it will be our title. And title will be
also of type string. One more will be description. Here we can use
parameter default, and here will be
an empty string. So we already used
the default here. We can say that
the default value inside this column
will be empty string. Here now we have our
description of type string. One more will be body. So here we have column default, again will be empty string. And here we have our
board is string. And if you are asking from where I am taken
all this columns, this is our specification. We're describing
all these columns. So after body we have
created at and updated it, there is a special notation for a typo RAM to use
these two fields. Because actually we
want inside to write timestamp of when we
created the article. This is why we're
writing like this. So here we have a column
and here will be created at this is y here we're
setting type timestamp. And next we need here
to provide default. Default for us will
be the default value because actually
we don't want to provide it by ourselves, but it will be auto-generated, which is exactly what we want. Here. We want to return
current timestamp. In this case, for this column will be used the
default timestamp, which means that time when
our entity was created. Here we can say that
we have filled created ad and it will be of type date, exactly the same we will
use for updated at. Here we have timestamp, current timestamp, and here
we have our updated at. The next thing that we
have is our array of tags. So as you can see here, we have add tag list, and this is array of strings, which means we can provide now a single article when
we're creating it, this list of tags. This is y here what
we want to do, we want to create new column. Here we can say simple array. This means that inside we will provide some values as an array. Here we can say that we have deg list of type string array. For example, if you
don't know how to write some column or what type
of data do you need? You're always can open the
documentation of types of RAM and check their
water possible types you have for columns. And what you can use here
was our simple array. And the last one for us
will be favorites count. Here we have column and
it will be with default. The default will be 0. So y that this is the default number of people
who liked this article. Here we're right in favorites
count, which is a number. Let's check. We implemented all these fields except a favorited and awesome. Now I want to do one more thing. This is regarding
update the tet, and we're already did this
code inside our user entity. Here we used before insert. And actually we can do something when we're
doing insertion, for example, in this case, we wanted to hash,
our passwords, were also want to do here
something but with updated at actually every single time when we're updating the record, we must update updated at filled and it won't
happen on its own. We must provide it here. So this is why we're
saying before update. And this will be a Kohlberg. When we're updating
the record inside, we want to provide
update timestamp. We can name it how we want because this
is just a function. And inside we want to
say this updated ad, this is our property
equals new date. We're just saving
current date inside our updated at at the moment when
we're date in the record. This we're all fields that
we need for our article. Now, it is time to generate migration and check if our
table will be created. Just to remind
you, we can always jump to package JSON
and check our scripts. Here we have dB drop to
be created db migrate. Actually to create
a new Migration, we need db create. This is y. Let's jump to the
console and try it here, yarn db create, and
here will be our name. And actually here we can
name it create articles. Let's hit Enter. And here
is our new migration. As you can see, it analyzes
the migrations and our tables that we have
and create a migration. Let's check what we have here, resource migrations and
here risk create articles. As you can see here is our Create Table articles with all properties
that we created. Here is of course, drop table articles if we
want to revert it. Now let's try and apply
this migration for this, we need to write
Young db migrate. And actually we should not get any errors because we don't
have this table at all. As you can see, we
don't have any errors. And here this code was executed. So create table articles, In which means we're getting
in your article table. Let's check this out inside
PSQL here I can write d t, and you can see
that we are getting your table articles and
here we can write d. So describe articles to check what fields
were having inside. Here is ID, slug title, description, body and so on. And we can see that for
created at and updated at, we have here timestamp,
result Time Zone. This is exactly what we wanted. So actually we successfully created our base
module off article, and now we can
implement new methods.
24. Creating article method: In this video, we will fully create, create article method. And actually it will be
super similar to our method of create that were used for
registration of the user. We need a method
inside controller, will need a service
method that we'll do insertion inside
our database. And of course we need our detour to have a payload of
creating an article. Here I will jump
insights source, article controller, and
here is our create method. But we have here
something interesting. Actually, if we will
check the specification, you can see that for create article or authentication
is required. So actually this means
that we will have here user ID and
result this user ID. We can't really
create an anticoag because article must
belong to one user. Which actually brings us
to the topic of relations, wire relations, because we have now relations
between tables. First of all, we have the table of the users where we have, for example, NAD and
the name of the user. And we have a table
with the article. When we're creating an
article which should not only write their ID of the article
and some information, but additionally, we must store in every record
of our article, the user ID, which is the
owner of this article. This stuff is called
relations and normally ORMs somehow give us possibility to implement
this quite easy. And actually in last year's
will also have relations. Let's look how we're doing them. First of all, we must inside our article entity and user entity describe
this relations. Let's start with
our user entity. We must jump inside user and
here we have user entity. Here we have before
insert and after, we want to describe
that one user can have many posts because one user can create
a lot of posts. But actually one single post
can have only one owner. This is why only one user. This is exactly what
we want to write here. And actually I must say
here that what we are writing now with relations
is the part of typer room. And it's not written in
Super understandable way. You just need to accept this. And maybe it could be
based from documentation every single time when you
are writing relations. This is how it looks like. So here we have a
relation, one too many. Why? Because here we
are inside user and we have a relation with one
user and many articles. Now inside as the
first parameter, we must have an
arrow function here. And we're returning
our article entity. With such notation,
we're saying that our user can have multiple
article entities. Here as the second parameter, we have article as an argument, and here we're returning
article dot awesome. So actually now inside
every single article, we can write article.org
to get our awesome. This is really convenient
when you don't want to really additional
every single time, find the user by ID that
we will store in a second. But we can simply write
article dot author. And because of the
sugar of type I error, we will get it back. Now here what we can write is articles and here
is to go entity. So actually this is how you are creating the relation
from one-to-many. So you have one user, a lot of articles. And actually I can't say that this all notation is
super clear for me. I just took it from documentation and used
in all my projects. You can simply
always google typo RAM relations here reserve official documentation
and as you can see, where interested in one to many. And when we are jumping here, we can see exactly
this examples, how we're writing it now from the side of his
overwrote everything. Now we need to define it inside
this side of our article. This is why we're jumping
inside our article entity. Here on the bottom. We'll also must define it here. So what we want to
say is many-to-one, because we have a
lot of articles and they are belonging
to a single user. Now inside here we also have an arrow function where
we're returning user entity. So actually our user
entity is an ulna. Now here we have this user
as the first parameter and we're returning
here user dot articles. And now here we can name
this field for example, or some, and this
is user entity. In this case, we can say
inside every single article, article dot or so,
to get a user. Or inside the user, we can say user dot articles to get all articles
of this user. So this is how you are creating relations between two entities. And as we made our changes
for both entities, we're must create
a new Migration. This is why I'm
jumping here inside console and then write
in Yandi be Create. And here we can name it. For example, add relations
between article and user. Yes, the name is quite long, but actually from the name, we can really understand
what is it about. Here. As you can see, we are
getting on your migration. So let's check how it looks like here inside
source migrations. This is our new migration. And as you can see, this is the most important line for us. So alter table articles
and also ID integer. This means that now
inside article table we have a new column and
it is called author ID. This is why in every single
record that we're creating, we're must provide this also ID because we have this relations. Also important part for us
here is that now we have a foreign key or society and
reference to use a table. Also, as you can see here, we didn't provide any actions
ON delete or an update, but actually we can do this
and then Postgres will automatically fast do something
between these references. So our relations are there. Now we must do migrations. This is why Yan db
migrate will make great our database and bring
it to the latest state. Now let's check what
we have inside our DB. The interesting part here is
to write, describe articles. And as you can see here, that the main difference we
have here in your property, which is author ID integer, which means now when we're
creating an article, we will store here
are awesome for us is also important that here we have a foreign
key author ID, and it references users ID. You don't need to do
anything with it. But this is how it's
looking inside Postgres. Now, we're really ready to create our action
inside controller. Let's jump here back inside source article,
article controlling. And here we have
our create method. And actually if we
will check here in the documentation
of great article, you can see that we
again have somebody lot, which actually means
we must create a new duty or file
for this payload. This is why here I will
create a new folder DTO, exactly how we did
previously inside users. Here I can say Create
article dot d t dot ds. And here we can create our
new detail, our class. So here we have our class. This is great article
detail on the inside we have four fields actually titled description,
body tag list. And three of them are mandatory title,
description and body. So it stays here, which means we can say
that they are required. This is why here we have a read-only title
and this is strain. Now here we want to use a
decorator is not empty. Now here we also have
these not empty. And here we have a read-only
description of type string. And one more will
be is not empty. And here we will have our
read-only body of type string. And the last one
is not mandatory. This is why we're not
using here a decorator, but just saying here
read-only tag list. And here I want to put question mark because
this is not mandatory. And here we have
array of strings. This is our article
create detail, and now we can use it
inside our controller. So let's jump back inside
our article controller, and here is our create method. So first of all, we
can say here that this action is really
requiring authentication. Here under both, we can say use words like we
did previously, and here will be our R-squared that we created already
in previous video. This year's acquired means
if we don't have token, this token can't be parsed, then we're getting
401 unauthorized. This also means that we can
safely after the squad use here user from the request because we're sure
that we will get one. This is y here inside. Great. First of all, I want
to read our user. And actually we don't mean
the whole user but just NAD, because when we're
creating an article, we need to write
inside our user ID. This is y. Here we're
using our user decorator. And here we're reading ID, and this will be
current user ID. Then not talking a lot about
this code because we wrote exactly the same code inside
user in previous module. Here we successfully got our current user ID
and this is number. The second part that we want
to do is parse our body. This is y here will be body. And we want from body
to get article property because just to remind you here inside body we have an article. And this will be our
create article D2L. Here Let's name it,
create article D2L. Actually not with big letter. Here is create article DTO of type create article later on. And actually we didn't create an interface here
of our response. For now, I will simply
write here any, but we must of course create
here a valid response. And dissolve is just to remind
you been where hidden on article we have here
strange notation. So actually this is
our article entity, but we must packet in
additional property article. Actually it makes sense to
do exactly the same like in previous module and have additional function
builds response, which we'll back our
article identity correctly. But for now we
simply want to pass inside our great
article, the AD. So here will be current user ID and dour
create articles UTR. This is exactly what we want, but of course here we
need a wait to get back an article because here will be a
synchronous process. Now let's jump inside the
cytosol service create article. As I already said here we have current user ID and
this is number. And we have create article duty on of type create articles. And actually back, as always, we are getting promise
of our article entity. So just to remind you, we are getting here
plain data from database where not normalizing
them for front-end. Now here we need to create
a new article entity. And if you don't remember
here inside the user service, we did exactly the same. So here we have a
method create user. And as you can see here, we also had detail. And here first of all, we created new entity, then made object assign, and then simply use this
user repository save. We want exactly the same
logic, nothing new here. First of all, here we must write a constructor and inject
here our repository. Here I am writing
inject repository and inside I am right in
our article entity. Now this will be our private read-only property,
article repository. And it will be a repository
of type article entity. Let's close our constructor. Now we have this
article repository and we can use it
inside created article. So first of all, here we want to create a
new article entity. So let's name it
article and we're just colon here and
your article entity. This will create for
us an empty article. Now we want to assign
all properties from detail inside this article. This is why we're using
again object assign. And here is our empty article, and here we have our
create articles UTR. We simply add all properties
from create article detail. But the problem is here
that our task list can be undefined because
it's not mandatory. This is why here we
must try that if we don't have article dot doc list, whoop, want to create
one which will be empty. This is why here
we can simply say article pick list
equals empty array. This will create tick list
if we didn't pass one. The next thing that we want
to do before we will save the article is adding
a user ID inside, and we can do it
in different ways. First of all, we can simply
assign article dot yesterday, but secondly, we
can make it easier. So actually we passed
here current user ID, but a one just now to
change it to current user. Here we can say
that current user is actually our user entity. Now let's jump back inside
the article controller and change here user ID
just to play in user. So here we will have rarely
current user or user entity. Now we can directly set
this currentUser inside our article here we also need to remove current user
ID to current user. Let's jump back inside
our great article. Here we have current user
and we can say here, article dot or so. And this is the property that we created to make a
relation equals. And here will be
our currentUser. Why this code is better than
just assigning user ID. Because actually here
we're leveraging our usage of relations
and type RM. Because here we're working
with DOT author that was automatically created
for us by typer RAM. And we're set in here
full current user. And actually type or RAM will save everything correctly fast. Here we saved our author and now we want to save an article. This is why here we can return
and here will be weighed. And we're using here are
articles repository dot save and bison inside our article
that we want to save. Also, there is one more important thing
that we didn't do. We must register this type or RAM inside our article module. Let's jump inside
article module. And here we must provide
in birds and inside we must registered type where a
module here is for future. And inside we have an
array and web bison inside article entity because
we're using it inside. Let's now jump inside console
and check how it's working. As you can see here, we're
getting an error inside controller that we
wrote just any. But here maybe we
wanted promise any. And actually this
is a valid point because here we have a weight, which means we're
getting back a promise. Let's try it for now. Promise any, and we will
create a response later. Let's check this out.
Here is our web server and it works and we don't
have any validation errors. Let's now jump inside postmen. Here is our post
for great articles. And here I am just hit incent. As you can see,
we're getting 500, which means something is broken. Here to the problem. We have a null value
in column slug. And the problem is
here that he has, we have a property slog, but we're not passing
it from outside. And actually what we want to do, we want to create our
slug inside the service. But here I don't want really to implement
it in this video. We will do it in the next video. This is why let's just
say here articles slug equals four and we
will change it later. This is just for testing. Now what we want to do here, we want to make our
correct requests. And actually let's
jump in create article here is our request, so I will copy it completely, open Postman and paste it here because this is exactly
what the valid request. Now let's hit Send, and as you can see, we're
getting back the correct data. So here we have titled
description, bar detect list. This is what we provided. Here we have our slug that
we didn't generate yet. And here we have our author, which actually means that our relation was
correctly bind it. And now we have here author. Also we have ID and
here are our created at updated at which adjust
a normal timestamps. Now let's check in database
how it's looking like. So I will jump in pH scale. And here we can dry it, select star from articles. And as you can see, actually the output doesn't look that great and we
can't really read it. And actually there is a
pretty print inside PSQL. We can say here slash x, and it will enable
expanded display. Now let's try again, select star from articles. And as you can see, it is looking much better. So it's not looking like
table, but like columns. Here we have our first
record and we can see that everything is
correctly stored for us. The most important part
is here is also Id1, which actually means
that this line that we wrote here was
correctly processed by type and type where I'm saved inside database on
this id of awesome. Now we can always get all
articles of how author, or we can get the
author of our article.
25. Polishing create article: In previous video, we successfully created
our new method, great article, but we're missing here two
important things. First of all, we didn't
implement inside controller. I will return interface
because we have here any. And secondly, inside
our articles service, we have this placeholder
articles slug, and they actually were must
generate here a unique slug. In this video, we will
finish these two problems. First of all, let's talk about article controller
and this premise. And actually we want here to return the data
for the front-end. This is why we need
to take this entity. And as you can see here, create articles returns
for us article entity. And then we want to just wrap it in additional
article property. And we can do it exactly in the same way like
we did inside user. Just to remind you, here inside user
insert controller, we use the law to this, this user service
built user response. So actually we have a dedicated method to build
a front-end response. And we can do exactly
the same here. But first of all, we must
create here and you type, this is y here inside types
folder that I just created, we can create an article
response interface TS. Just to remind you, I'm trying to make
all interfaces in the same way we had user
response inside the user module. Here is article response. When naming things are the same. Now inside we simply need
to create a new interface and it will be our article
response interface. And inside we just want to pack our entity inside the
additional property article. This is why we're
saying here article is article entity and this
is all that we want. Now we can use this
article response interface inside our promise, any
insight controlling. And as you can see,
we are getting here and narrow because this is article entity not
article response interface. What I want to do
here first is create constant article
because secondly, we must create
additional function where we will build
our response. Here we can return
this article service, and here we will create a new function built
article response, and we will pass
inside our article. Now let's set this function. So let's jump inside Service. And here somewhere
on the bottom, we can create a function
build article response. Here we are getting as
an argument our article, which is an article entity
and backward returning our article response interface
that we just created. And inside the simpler returning an object with property
article, this is it. So actually we could write this code inside
controller. No worries. But the point is that we will
have a lot of actions here, and actually all our actions
must return the same format. So here we have created, we will also have update
or get or get filled. All this stuff is returning the article back in
additional article property. This is why it makes sense to create an additional
function here. And of course we
must resolve here article response interface
and import it here. We covered all our datatypes correctly and we're good to go. Now we must implement
our problem with slugs. So actually, as you can see, an article service here
we have articles slug. The point is that
we don't want to provide article slug
from the frontend. We must generate it
on the backend after creating an article
exactly here. But the problem is what
is slug normally it is dashed or underscored version
of our title, for example. And actually I highly
recommend you to use a popular package and
not reinvent the wheel. This is y. Here is the package
slightly phi, as you can see, it's
really popular. And the main idea is
that it correctly transforms strings inside slugs. And actually we should
not worry about other languages or
career like for example, symbols, UTF eight, whatever you can imagine, you simply use Liquify, you throw inside some title and then you are
getting back a slug. Also here we have some options. For example, we can convert
everything to lower, or we can replace spaces with dashes or underscore
or whatever we want. And of course we can
save here located. But for us it's really simple. We just want to use it and
transform to lowercase. But the main problem is
here That's liquefy, doesn't know anything about
uniqueness of our slugs. And actually every slug
in our project must be unique because this is
how a unique identifier. This is why we need to
extend it a little bit. First of all, we must
install this package. This is why I am
champion and said console and try it in
yarn adds log of phi. So this will install
our package. The next step is to chump inside our articles service tiers because we want to use it here. So here we're in Bertin slug
e phi for Rome sluggish Phi. This is fine for us
now we must use it. But the main problem, as I said, that it
must be unique. And the question is how
we can make it unique? And actually we can just
generate some unique theme and add it to our string that was
generated by slightly fine. This is why I wanted to show in the console how I want to do it. First of all, we can
use here math random. And as you can see, Math.random is given us back a flawed, which is actually unique but
not exactly what we want. We want to multiply
it on math Po. And here we have 366. If you don't know what mass
policed, It's a power, which means it returns a value of the number to the
power that we gave. This is why here we have
four and the power of three. Here we have 36 and
the power of six. The main idea is that
here we are getting really large number because
we want to get here the int. And we can get it
by using bitwise, OR this is where
here I have pipe 0. And as you can
see, we're getting here nice integer which
is completely random. No worries if you don't
understand this code exactly, you can simply reuse
it everywhere. And this is the way to
generate unique IDs. And the last step that
we want to do with this integer is just to
wrap it inside brackets. And right here, two string here, for example, will be 36. As you can see here, we're getting a nice string
which is really unique and regenerated this with
the help of math random. So I will copy paste fully
this line and actually create here additional method that will generate for
us unique slug. Here we can say private
because actually we don't want to reuse
this method outside. This is just for our service. Here, Let's name it, get
slug and inside where bison title and the D string and backward wanted
to get also a string. Here we can write return and we're using
here slightly phi. And we just need to pass
a title to this Liquify. So here we have title
and some options. I want to make it to lowercase. This is y, here is lower true. Now we want to
concatenate it with dash. And then with our magic string. Actually solidify
will generate for us nice slug from the title
and it will be lowercase. Then we have a dash, and then we have
our unique stream. Now we can simply
use this function in this place where we're
generating articles slug. Here we will have get slug
and we're biasing inside from the TOR create
article utah dot title. Let's check now if
it's working at all. So here we have our web
server, no arrows here. Let's jump inside. Postmen is you can see
here we provide a lot of information and our title here is how to
train your Dragon. Let's hit Send. And as you can see here, we have a slug. We have here how to
train your Dragon. This is slug defy. Then we have dash
and our unique ID, which actually means
our slugs are looking really nice now and
they are really unique.
26. Get article by slug: In this video, we will implement getting of
the single article. They really think that
you must try and do it by yourself because it's not that difficult and
we prepared a lot. So let's check what
we want to implement. As you can see here,
there's our specification and we have get article URL. Here is good for slash api
slash articles slash slug, which actually means that
this is not a static URL. But here we have a
dynamic parameter slug, no authentication required here, and it will return
a single article. And you also didn't know how single article is looking like. This is exactly what
we want to implement. The hard level for
you is just to pause the video and try to
implement it on your own. The second level,
which is medium, is with my guidance. So actually the question, what do we need here? We want here inside our controller to
implement and new method, and here will be get
method to get our article. And the only interesting
part that we didn't do previously here is getting
programs from the URL. Actually before all our
programs were stateless. And now we have this parameter slug and we
must read it from this URL. And actually inside
nest chairs we have a decorator which
is called params. When we need to get such parameter which is
dynamic from the URL. As you can see inside
the creditor per gram, we can simply
provide the name and actually it will read
request dot params like we have for
example in Express were written this program
and then by this slug, we can get our article. So actually this means that
in our service we must create a new method that will fetch our article from
database by slug. If you want to try
it by yourself and they highly
recommend you to do it, then just pause the video now, and here we have the easy level. Let's implement it together. So actually here we want
to create a new method. So we know that this
has a getMethod. So we're right in here. Get decorator would
don't need any words. And this is just a sinc function
to get a single article. This is why I will name it single article or actually
get single article. It doesn't really matter
what we want inside. We must read a
parameter from our URL. This is why here we will get per gram decorator and
inside we will pass slug by slide because actually here we have this
unique slug part. But now of course
the question how unless JS knows that this is dynamic parameter and actually we must provide it inside get. To do this book
can provide inside get colon and then slug. In this case, we're
saying that our URL is slash articles because we defined it in our controller. And after articles
we have slash slug because here we
provided colon slug. And then this params slug is exactly what we provided here. Here we've got our slug and
we can say that this is our slug of type string
and we'll know that back. We're getting our article in
the same format like always. So here we have our premise of article response interface. So it is wrapped inside in
additional property article. Now inside here we
want first of all, to get our article. And for this we need
one more method from our articles service
and we can name it, for example, find by slug
inside wealth by sin, our slug. This line we will
create in a second. But afterwards we want to use our this article
service built article response variable
bias our article. So actually this line
we're already used instead create nothing new here. We just need to create
find by slug method here. So let's jump inside our
serous and here for example, after Create, create
a new method. And it will be find by slug. Now inside we must
provide our slug, which has a string back. We will get as always promise of type article entity because we will get our article
entity from the database. Now here we can use find one method to find
something biofield. What we want here is
returned a weight. Here we have our
article repository and again we're using find one. We already did it previously. Actually inside find one, we can throw their
AD directly or we can throw the object and
pass here some fields. For example, we can
write here slug field. And this means that
we want to find one single record by this
slag that were provided. And actually slug is a column
inside our articles table. So actually this
single liner will return for us a single
article from database. If slug is not unique, then it will take the first
article that is possible. Now let's check if it's
working. So let's jump in. Our web server is you can
see we have the error roofer Gordon side
controller to import get. So let's jump back inside
article controlling. And here I will import our GET. Let's check again. As you can show, a server is restarting and I think we
don't have any problems. So now let's check our postman. For this. We want to
create a new URL. So here will be slash, articles slash, and here
must be a slug that exists. And actually I
will take our slug that we just created and paste it here because this is the unique slug and they also
want to save this request. This is why Save
As and here is get single article and we're saving it in our
collection nest Jess, Here is our request. This is of course get and not post body doesn't really matter. Here we're hitting send regard our article which is backed in additional
property article. Here are all our fields from
database that we saved, which means we successfully implemented our get's
single article request actually in a matter
of minutes because it was usage of type
eardrum and nest js, we can implement our
API really fast.
27. Deleting the article: In this video, we will implement
deleting of the article. You might think that
all our actions actually really similar
and yes they are. But sometimes we have
something interesting, for example, in
our delete method. So actually if we check
our documentation, so here we have delete article, which is a delete
method for slash api slash articles slash slug. First of all, we have
here our dynamic part, This is our unique slug, but the most interesting
part here is that our authentication
is required. So actually this means that on the login user can do this
request, but it's not. All. The point is that
only the author of the article is allowed
to remove this article. Which actually means that
inside a method inside service, we must check if current user is rarely the author
of this article. In other case, we don't
need to allow this. Let's implement it now. I will jump inside our
article controller, and here we will create a
new method which is deleted. And this just saw here
we have a delete slash, api slash articles slash slug. This is our base euro, so we just need to
implement slug for delete. This is y here
we're saying slug. And as you can see,
actually we have here get with the same
string as here, delete. And it's not a problem at all, just because here we
have delete and get, which actually means these
are two different routes. One with the method get and second with
the method delete. Now inside, Let's create an async method and let's
name it, delete article. Now the question is what
we want to get inside? First of all, current
user and secondly, this slug parameter
from the URL, this is y here,
exactly like here, we will use per gram
and user decorator. First of all, we need user ID. This is y, here is user ID, and this will get for
us our current user ID. Here I have current user
ID and this is a string. And the second thing
that I need here is per gram of slag, and this will be our
slug of type string. Now the question is what
we are getting back? And actually it's
not specified here. And normally people are not wait in something
here in return, but actually we will
specify it later. So here I will just open our function and actually
our function is ready. The second important part
is to use here a word. Here we want USC words. And here we will have
our outer world, which will check
for unauthorized. Now inside we just want to call a method from service
as we did previously. And actually here
I will just simply return the result of
this service. Why? Because actually
here inside span, we don't have any specification
what we want to return. The easiest way. It just not to think about
normalization of the data and just throw out what we are
getting from our type ramp. This is where here I will return a weight because this
is a long process. And here we will have this article service and
let's name it delete article. Now for delete article book
wanted to provide insight, first of all our slug and
then current user ID. So here we have our
slug, current user ID. Let's jump inside our
articles service. Here. It doesn't really matter where
I create a new function. So it will be a sinc
function delete article, and inside we first get our slug and second
current user AD. And actually back,
we're returning here promise of delete result. You may task what
is dilute result? As you can see, I'm outer
importing it from typo around. And actually it
returns an object returned by Delete query
builder execution, which actually means that
this is the response of type or RAM when we're
deleting the record. And you will see how it
looks like in a second. But actually this is exactly
what type or RAM returns for us when we're
deleting something. The next step here is
to find that article. You might task why
we need to find the article if we already know that slug is unique and we can just remove a record by slug. You are totally right, but we must fetch an article. First of all, to check that
this article exists at all. And secondly, to check the
author of this article. This is why here I
will write article. Here. We can use
this fine by slag. And just to remind you, we already created
this method before, this is simply find one by slug. Here is our article and
the first if here will be, if we don't have the article, then we want to throw new error. Here as always, we have
should it be exception? Here we can provide some stream. For example, article is not
found or does not exist. And second livable
provide here status. So here we will have HTTP
status dot naught found. It will be 404. So this was our first check. Our second check is to compare our current user
ID with author ID, and this is really easy to do. We just need to compare
here article dot or dot ID. This you can see
actually here we have directly author
on the article, but for some reason
it's not there. Let's check this out. If we will jump in
article entity. Here we have this
many to one relation, and here we have user articles. So this was for user. Now when we're
jumping back, here, we have our relation
between user and article. But the point is
that by default, if we're just getting an
article from the database, which just get an article with don't get article
with all relations. This is why we actually can specify here inside
configuration that we want to always get an author when we're get an
article automatically. First of all, this is
really convenient for us. And secondly, if we will
check all responses, for example, here
inside article, you can see that we
always get an bag, this also part, and actually
this part is our relation. And this is really easy to do. We simply need here after
the second parameter. So here we have many-to-one
first function, second function,
then here is coma. And we're saying here, eager through this option
means that we will always load automatically
or so for our article. And actually you even don't
need to open documentation. You simply can highlight here, award and check
what is it about. So as you can see here, eager relations are always
loaded automatically. This is exactly what
we want in this case. As you can see, our error
is not gone at all, which actually means I wrote
something not correctly. We're getting here the
problems that it does not exist on type promise
article entity. Actually here I simply
forgot to write a rate. This is why here we didn't
get back our article entity, but we got previously a promise. So this was actually
the problem. But in any case, this eager true when need for all
our API responses. This is why it's
good that parotid. Now here actually we need
to write not a rate, but simply IV article
author ID equals. And here we will have
our current user ID. We simply compare
these two ideas. And as you can see,
author exists on type article and this
is our user entity. This is exactly what we want. So actually if they
are not equal, in this case, we want to
throw the error inside. If I will simply copy paste this throw because we just wanted
to throw an exception. And inside we can write u, r naught and awesome. Here we of course will
throw forbidden because in this case we want
403 and not 404. So actually we checked all
are exceptions and now we can simply allow to remove an
article for this weekend. Return here a raid because
we're making the request. And here we have our this article repository and here is the method delete. And as you can see, we can give insight
accurate area or NAD. In our case, it
doesn't really matter because we have both
here inside article, we have an AD or we
can delete by slug. Actually here we
can write like this and this will be
removing by slug. And here inside we can provide
whatever options we want. But for us, slug is
unique identifier. This is why it will
work correctly. One more problem
that I see here, I forgot to write here that current user AD is
actually a number. Now, we wrote
everything correctly and now we can jump back
inside our controller. So as you can see,
inset controller, everything is working here
with our delete article. As you can see,
we're passing in set current user ID and it is read and it is red
because here we specified that it should
be number inside. But here for some reason
I wrote the string. Of course, current user
ID is always a number because all a decent sized
portraits are numbers. Let's check if it's working. As you can see, no errors here. Let's jump inside postmen. Here we have an article with
our slag, so it exists. Now, I want to make here delete and make of course save as here, we will have our delete article. Let's save it inside our
next chess collection. Here I'm saving it. We have delete. We should not provide anything
except of headers. Here the token is important
because we must be login. Now let's hit Send. As you can see, this
is our response. Here we have raw and effect. It actually affected means
how many items were deleted. And actually for our delete, it doesn't really matter if
we give any response or not. But here it was easier to
simply specify the same stuff, but we are getting
from typo RAM. And as you can see
inside Service, this delete result is
exactly what we got here, so it was wrong and affected. Also, let's check
if, for example, our board is working correctly, or at least any of other code. Here, I will simply type something so our
slug is not valid. Now I'm hitting sand
and as you can see, we are getting the
message status code for 0 for message article
does not exist. As you can see, our condition here is completely
correct and we're throwing an error when our slug is not found
in the database.
28. Updating an article: In this video, we will implement
updating of the article. And actually it will
be super similar to our great article
and delete article. This is why I highly recommend
you to try and build it on your own because it is
super beneficial for you. And as always, we have here
three levels of complexity. Level one, you are just
implemented by yourself. So let's check this out. Here is our spec update article. We have a PUT request to
slash api slash articles, and here is our unique slug. This is the example of the
request, and as you can see, it is a little bit different to our Create because here it
didn't provide all fields. We simply provide
a single title. And as you can see here,
authentication is required. We're returning
updated articles. So the same response as always. Here are optional fields, title, description, and body. So actually this means
that we should not provide even all fields
if we don't need to, but just optional fields
that we want to update. The main problem is here that
I really think that this is a bad approach because this is really bad for the front-end. Why? Because normally you have a form in front
of you and you're creating an article and you are getting this
validation messages, this is completely fine, and it is exactly how
it is inside spec. Then when you are inside update form and you
are removing fully, for example, a title, then you are hidden update and you don't see
any validation. It simply closes
the form and show you the article which
was not updated. This is not a good
UI because from my perspective and from
all normal projects, your grade form should
be consistent with update form and actually
all validation messages must stay the same. This is why here we will
implement not optional fields, but all fields are required in exactly the same way how they
are required for create. And actually it won't make
any significant difference. And all front-end projects
will work correctly. If you want to try and
do it by yourself, just pause the video now. Level two is my guidance. So actually, as I already said, were born to make all
fields mandatory. Already created in D2L, this create articles deuterium. And as you can see, this old
fields are already there. So these three fields like titled body description
are already mandatory. Actually, we can either rename this dto or simply use
it for create article, the same detour for update
and implement creation. So as always, we must implement new action and new
method inside service. And actually for us, the interesting
part, first of all, we must through this slug. Secondly, we must read a
current user ID because authentication is
required and we must check if we are allowed
to update this article. And of course we need to get an article body which
will be detailed. If you want to try and
implement it by yourself, just pause the video
now and try it. And level three, of course, let's implement it together. First of all, I will jump
inside our controller. This is article controller. And here we want to
create update article. This is y, here will
be put and here I will also write slop because this
is our dynamic parameter. Also we must use here u squared because this action is
only for registered users. Inside we're passing
our outward. Now we have here a sinc
function update article, and we need several things. First of all, user ID, because we must get
a current user ID, we're doing exactly the same like we did for
example in delete. The second one is slug. So here we have our program
and here is our slug, and we will create a local
parameter slug of type string. The last one here
will be our body. So our detail, and
we can write here update article detail on here. I will simply write
great article Detroit. And it may sound like
a little bit not valid because we're using detour
for create inside update. If you don't like this approach, you can always rename this
great article duty to, for example, persist article. So it will be genetic
between create and update, but it doesn't really
make any difference because this is simply
our class for validation. Now what I want to do inside is first of all get our article. Actually the result of our update method is as
always, our article. Then we want to pack it inside our normalizer function
built article response. So we're creating the correct
response for our front-end. This is why here we have
our article and we're calling await this
article service. And let's create new
function update article where inside we must
provide first of all, slag, secondly, update
article detour and of course, our current user ID. And after this we can
call here a weight, this article service,
build articles response. And we're bison
inside an article, exactly how we did previously. Let's save this and jump
inside our article service. Here we have our delete. Let's create a new function and it will be our
update article. First of all, we're
passing here our slug. Then secondly we'll have update article details of type
create article detail on. And last but not least is
of course current user ID, which is actually a number. And I again wrote it
like string, I think. So let's check this out. Here is our current user ID. Yes, I wrote here number,
everything is fine. So these are our
arguments and back we're getting our promise
because it is a weight. And inside we have
our article entity, which will be our
updated record. And actually here we can copy
paste code from our delete. Because actually we
want to get an article from database by
slug to check if it exists and to check
if we're an awesome because only an author
can update the article. This is why we can
simply copy paste these three lines because
they are identical. Here. First of all, we're fetching
this article from database. Then we're checking
if it exists. If not, we're throwing
the error and then we're comparing the author ID
with our current user ID. The last step here is to update
our article and save it. This is why we can write
here object assign, like we already did previously. And here we're calling
assigned method, and here will be our article and we want to override
some properties with update article determine
the main point is here that we don't care
what properties are inside, which actually means
both variants are fine for us, either
optional fields. So these three fields
are just what we passed or all fields it will
work in any case. Here we updated
some fields inside our article and now we
want to save it again. So here we are
returning a weight and here is article
repository dot save, and we're passing
inside our article. So this will update our article correctly and return
our article entity. Now let's check if it's working. So I'm jumping here. As you can see, we
have some error. Cannot find name put
inside our controller. For sure I forgot to import it. We are jumping here. I remembered to input. Let's check once again, as you can see, we
don't have any errors. Let's jump inside Postman and
try to remove an article. The main point that I think
I don't have any articles. Let's check this
inside database. So here is my PSQL, I am right and select
stuff from articles. And as you can see here, we have one article
and the slug is full, so we still have one
article that we can update. This is why I'm jumping
in and said Postman, here we have slash
articles slash foo. This will be pulled
and they want here to Save As update article. Now here let's save it inside nest GS collection and
dried correct body. Just to remind you how
body is looking like, this is article field
width for example, title, and we made actually
all fields mandatory. So let's check this out. I will jump here inside,
right, Just article. And inside of article we have, for example, simpler title. Here I will write bar. Let's hit Send. And actually we are
getting here update, which means we didn't validate all our duty
or that were created. And this is totally correct
because we didn't try it. Validation of detour
here inside our pool. Just to remind you here inside Create we have a
validation pipe. Actually we forgot to
write it completely. This is why here we have
only Guan's button, not a validation pipe. And for sure we want to
validate our request, like create and update. This is why here I will
write use pipes and inside we must provide
new validation pipe. And let's just call it
out with round brackets. And we need the same
code inside our update, for example, under guards. Let's check it once again. Here everything is fine. I'm jumping into Postman
and hidden sand. And as you can see
again, no validation. I really miss something. Yes, I can see here what,
as you can see here, we use two decorators to get a user and to get a parameter. But here we didn't
write any decorator, which means actually this
code is not providing a tone. This is why it's not working. What we want to write
here is our body, because we want from our body
to read article property. And in this case,
it must be correct. So as you can see,
no errors here. Let's check again. I'm hitting sand and here
are our error messages. It is super important
that you are getting correct information
from the URL. As you can see here, we have
all three validation errors because this has the same
fields, like inside Create. Let's provide them now
here we have our title. I don't know what
title was there, but I think not this. Then we want to update
our description. Here we have, for
example, bar description. And the last one will be body, which is Barr body. Let's check this out. I'm hitting sand
and as you can see, we don't have any errors. And inside we have
our new title, new description and new body, which actually means
that we successfully implemented our update and
of the article barred, you should be really
careful when you are right and thins
inside controller because it is
really easy to miss a decorator and then
it just stops working.
29. Creating feed: If you've watched all previous
videos in this course, then you probably
already mastered create an update and removing
entities and finding them. So actually you have enough knowledge to
create your own modules, your own actions, and create
tables for this entities. This is why starting
from this video, we're going in more
advanced stuff. And in this video, I want
to implement our feed. Let's have a look. Here. We have the URL
slushy by slash articles. And actually this URL
just returns the array of our articles starting
from the recent articles. But there are a lot
of query parameters. First of all, we
can filter them by tag and actually
just to remind you, but already created tags, then we can filter by author, will already have author. We can filter it only
by favorited user. We don't have this
functionality yet. Then we have of course, limit and offset to handle
how many articles we want to return and what
offsets and skip would have. Also authentication
here is optional, which means we can return this request for not
logging in users. Now the question is why I am thinking that this request is interesting because we can't
really implement it easy. We simply using repository
like we did previously, because we have here a lot
of different parameters and we can't write a simple
usage like for example, find the find one because
a lot of conditions here. And normally if you want
low-level stuff where you can configure everything we're using for this select query building. As you can see, this is the link to the recommendation
of types of RAM. And as you can see here, I opened select
using query builder. So actually the idea is
that what we're using this type of program to select
the data is query builder. So we're building our
queries for database. Let's have a look on a simple example as
you can see here, we have connection
then Git repository. Here we're calling
Create Query Builder. We're not using
repository as previously, but we're creating
query builder. And after we're
calling this function, we can use a lot of
different stuff. For example, where when
we want some condition, in this case we're saying
here where user ID equals AD and here
we're bias in the data. Here, then we have
such SQL query. And of course this
is really nice if you understand the
scale queries. But the idea of typography
is that we're thinking less about our SQL queries because
we have a nice wrapper, just risk plane methods where we can define
what we want to get. This is why we will use here Create Query Builder
to make this request. So let's get started. First of all, we are jumping inside our article controller. Here on the top, I will create the new function y on the top because
they actually, this is the first function. This is find all
OR gates and feed. Actually here we have a get and this is good for our articles. Now inside, let's create
the function find all here. First of all, we
want to get user ID. The beginning. We don't need current user, but later we need to
understand if we would like to the article
in the list or not. This is why I will from
the beginning pass here our user ID because
we need it later. This is our current
user id of type number. And the second part that they
want to get here is query. What is square? This is an object
result very params, as you can see here, we're
working with queries. This is why here we have
this question mark. Everything that is going
after question mark is query parameters. To get query parameters
where using query decorator, we're simply type in here
query and then we're getting the object with
all our parameters. And of course we can get a single parameter if we
will provide it inside. But actually in our case here, we want to get all parameters. This is where here I am creating local property query and they
actually it is of type any. And actually book could
type our query because we really can't specify what
query parameters are allowed. But for now I will
simply write here any, because actually
people can throw any parameters that
they want inside here. Now back, we must return
in your response. So actually let's check what
we are getting back here. I'm hitting multiple articles. And as you can see,
the idea is that we don't have here
property article, but articles, and
this is the ray. So this means that here
we want to create how you interface and let's name it
articles response interface. Now inside we must call a
function from our service. But the point is that service will give us the
data in this format. As you can see, first of all, we have here articles property
and this our articles. And after we have
articles count, this is our total articles count which we need
for pagination. And actually here we
will create a method that will already normalized
and prepare data. Because here we won't have
additional function like we had here with this built
articles response. This is why here I
will directly write a weight and here we will have
our this article service. And now let's create
here, for example, find all function wherever bison our current AD and query. The next step is to create this articles
response interface. For this, I will jump
and say types and create articles response dot
interface, dot ds. Here let's create
our new interface. And this is articles
response interface. Now inside we have
two properties. First of all, it has articles. This is the array
of our articles. Here we have article
entity, an array. And after this we have
our articles count, and we'll know that
this will be a number. This is how in your article
response interface, let's use it inside controller. I am outgoing button it, and we're good to go. Now we just need to
implement this method, find all inside our service. So let's jump inside
our articles service. And here, create this function. We have here a sink, find all, and we'll know that we're
getting, first of all, current user ID and
this is number. And secondly, we are getting
here query of type any. And the back we will
get our promise of type articles
response interface. Now the question is what
we will write inside? And there's already showed
you here in the example. We will use Create
Query Builder. How we can create it. Actually here I will create
a property query builder. To create it. We can write here
Git repository. And as you can see, Git
Repository Function is a new function
from topos or RAM. Inside we must
provide an entity, as you can see here we provided inside, for example, user. In our case, we want to provide insight article entity because we're working with article. The next one is dot
Create Query Builder. As you can see here
in the description, we can provide an alias
here as a string. This is exactly what
I want to do because then it will be easier
to build our query. Here I want to
write ILS articles just because our table
is named articles. And in this case, when the standard better
what we are talking about, the next thing that we must
do here is Lord our awesome. Just to remind you here
inside article entity, we have this relation
for author many-to-one. And actually we already used it here when we saved our article. Here we simply wrote article
author and it was saved. And actually if we are
doing our requests, for example, was find one, then we're getting inside article entity
automatically this author, because here we have an
option you go through. When we're building
our query on our own, we must do it by ourselves because we are building
query from scratch. This is why here we have
Create Query Builder, and here we must say
left, join and select. What is the DEA normally inside Postgres or any
relational database. When you want to
build some selection of the data based
on several tables, you are using giants, which means you have a
table one and you are joining to it data of table two. This means that for example, for every record in table one, for example, we are
talking about article. We have inside author ID. And by this author id, we're joining all data regarding this awesome,
inside our request. This is y here I'm saying
left, join and select. This means that we're joined
in here and another table. And here we must
specify articles.org. This is the field where
we want to join it. And here we will have awesome. This is what exactly
we will join. As you can see here when
I select this function, here are two arguments. First of all, we
have here property, and secondly we have here Alice. Actually also is our alerts
and articles dot Orissa, exactly what we're selecting. Now let's check that
this code is working at all without any
additional conditions. What I want here, first of all, I want to get all
articles by this request. So here I can try articles, and this will be our array. And here we're saying a
rate and we're calling query builder dot, get many. As you can see, get
many gets the array. And in this case get one will
get unless single record. And we need here an array. So this will return for us
an array of article entity. The next part is to
get articles count. Here I will create
articles count. And here we're using a
weight Query Builder. Here we'll get count. So actually it takes
this request from the Query Builder and
just gets the total. So now we simply need to
return this information back. This is why here I am returning articles and articles count, and this is exactly what we
specified inside our request. Let's check if this
request is working at all. First of all, we don't
have any errors here. Let's jump inside postmen. We have slash articles request, and this is again, they want to save as it here. And here will be our feed. If, for example, articles, and we can save it inside
our next GS collection. Let's save it and hit Send. As you can see here, we're
already getting our data. So we have our array of articles where we
have a single article and here is single articles count because we have
only one of them. The most important information
here is this author. Actually by default
we're not getting it. And just because we
wrote here this left, join and select who were
getting eat additionally. Now let's start to
implement our conditions, and let's start from
the easiest ones. So actually here we
have our request. So let's look for
slash articles. And as you can see
here are our filters. The easiest here our
limit and upset. And if you don't know, the idea is that
in the limit where set in how many items
we have per page. And offset means how
many items we must keep. In this case, offset 0 means
that we're on the start. We're showing the
items from 0 to 20. If we're on the second page, then we're showing items
from 20 to 40 and so on. And actually limit and upset are working out of the box
inside type where m, This is why it is super
easy to implement. What is the idea? Actually, I want to move
this articles request on the bottom and just after
articles count, right? My if condition. Why is that? Because articles count must
return the total faster. And if we're using
limit and offset, then we will get on
the specific page. This means after we're using
it on our query builder, we can't get total anymore. This is why I am making
this request after and then we will get our articles
was modified credible. Then what I want here is right, if we have query dot limit, so we're provided limit
in our parameters, then we want to say
query builder dot limit. As you can see,
we're getting out of the box this function limit, and we simply straw inside query limit and it
is just working. The same part is coding
for our query upset. So we're saying if here we
have our query dot offset, then we want to
apply our offset. So here we have query
builder of set. Here we're biasing
our query dot offset. Let's check if it's working. But for this, of course, we
need to create more articles. As you can see here we
have great article. Let's try to create new one. Of course we're
getting some errors. Here. We need to provide a valid
title and valid body. Let's name it body
and also description. So let's throw here for example, description. Let's hit Send. As you can see, we
created new article. I will hit send a lot of times. So we're creating a lot of unique articles and we
have a nice pagination. Now let's try if it's working. So we have here slash articles
and they want to say here, limit equals to offset equals 0. As you can see here inside
our array of articles were getting only two articles because they said here limit to, but in articles count
we're getting our total. So in total we have 17 articles. And they are starting
from offset 0. As you can see here,
our articles have slug full and here slug is
GGG and then the slug. If I'm setting here of
set six for example, then we have different items. So here we have already
different slags, which means we are
getting this logic out of the box and it just works. The next step is
to apply sorting. Would want to see recent
articles on the top. This is where here for example, on the top, we can
write this code. We want in any case without any, if you apply this certain, this is why here
we have ordered by function and we can
provide insight articles, this is our table dot and
here we have created at, and just to remind you, created at is our
field inside table. Here we can say this sentence. So actually as a
second parameter, we can provide either
ascending or descending. This you can see here
in the recommendation. In our case, just by
applying the single line, we're sorting all our
articles with descendant. So let's check this out. I'm jumping into Postman
and here is offset 0. When I reload the page, you can see here I dynein, which actually means
this is the US items. So actually they were sorted. The next thing that we can apply here is filtering by tag. As you can see here, we
can provide query tag and then we can simply
sort by this ten. What does it mean actually
inside every single article we have the list and actually we didn't fill it
almost anywhere. But at the first one record, we have this article. This is why here I
will say limit 20. And then somewhere on the
bottom, as you can see, we have the glutes with React chairs, dragons,
and AngularJS. So actually the idea
is that we can filter, for example, on the items where inside tech list
we have dragons. So the question is
how we can write it? For this? We can write here if. And here we're
checking if we have query dot tags
were provided tag, then we want to use
here query builder dot and where, why and where. Because actually rare
means that we can provide only a single condition
when we're using and where this means
that we're throwing new and new where conditions
inside our query. This means that we can create several ifs and inside
every IV, right? And where this is
exactly what we will do. What I want to do here
is provide our logic, means that we're applying this logic to our query builder. So here I want to write
articles dot tag list. And inside we have like and
here we have colon tag. Now here as the second parameter I want to provide an object. And inside I have tagged where I have Atmos crypt six string. So what I want to write
here is present and then dollar and inside
will be query tank. Now the question is
what I wrote at all? So actually if we
are talking about Postgres or normal
relational database, we can write here for
example, some field, for example, articles,
text list like and like means that we're finding
substring inside our string. And actually tag
list is a string because we're storing in
our array as a string. If you don't believe
me, let's open PSQL. As you can see here, we made the request for our articles. And here our tick list is
just comma separated string, which means that this slide
will work because we're finding substring
inside our string. Here we have our string
articles stick list, like means inside,
so like concludes, and here we have colon tag. This actually means that we will use this construction inside it. This means that we're not looking for the
strict occurrence, but we can also find
a part of the string. And actually if you
have some questions regarding query builder
or how to create queries, you can always jump here in
the documentation and look for examples with and where
and how you can drive them. Now let's check if it's working. So I will jump here inside
Postman and dry it here, result, limit and upset because we're
already tested them. Tag equal dragons. As you can see here, we successfully
found our articles and here we have only
a single article. We're inside, we have task list. This is y here inside
we have dragons. There is a match. This is why we're returning
here a single article, which actually means that our filter is working correctly. The next is that we
can implement is this logic with awesome
equals and then the name. And actually it will be really
similar to our query tag. Here we can try it if we
have query dot author. So we're providing
an author and whoop, want to get only the
articles of this person. Then here we can write query
builder and here n square. And inside we have our logic. So here we have articles,
thought awesome ID. Here we have equals and
here will be colon ID, exactly like like tag. But here we have really equals. Now here we have an object with our parameters and we need
to provide ID parameter, which will be also id. The question is
what is author ID? We don't have it here. That this means that if
we have this option, we must get an author here. So we must get here
a user entity. This is why here I
will write const or so we will finish
here and author. And here we must write a
rate this user repository. And just to remind you, we are inside article
service naught in user. This is why here we
must also inject user repository if we
want to work with it. Here I am writing
user repository, and here I want
to call find one. And inside we're passing
user's name equals query dot. Awesome. We want to find the single user. Here we're finding our author, and then we're
passing here inside our request also dot ADD. But the point is that
we don't have here user repository and we must
inject it here on the top. So actually I will copy
paste this two lines, just paste it here, rename article entity
to user entity. Here we have then
read-only user repository. Here is our repository
of our user entity. But it is also not
enough because we must provided also
inside the module. This is why I will jump
in article module. And here we have this typo
REM module for future. If we don't provide
here our user entity, then it won't work. This is why here
we need to write user entity because he was
an entity is a dependency. Now of our article module, let's jump back inside
our articles service. As you can see now we
don't have any errors. Here. We're getting our author and we're biasing it
inside our request. Let's check if it's working. So here is our server. Everything is working. We're jumping and say Postman. And here we're saying or so. And actually for now
we have just a single awesome and I think
this is the ASO full. Let's hit Send. As you can see, we
didn't get any articles, so probably I typed our
OSCE are not correctly. So let's check the user's
name inside Postgres. So here I am right
and select star from and here we have users. And these are all
users that we have. So we have here email
full at gmail.com, then one more time, food gmail.com and so on. Because actually recreated them before we used our
validation pipe. So this is why we
have duplicates. And actually this is
exactly the problem. As you can see here, we have several users with
the same username. First of all, it is
forbidden in our system. And secondly, we're
using here find one because we're thinking that
our username is unique. First of all, we must
drop our database completely just because
this is invalid data. But our problem is
that we're finding first occurrence
with username form. And probably we found here a user that didn't
create any posts. So actually our code
is working correctly, but we can't test it. This is why I will
jump here inside console and run Yarn dB drop. And this will clean all
records inside our database. Now is we don't have a database, we must run our migrations. This is where I'm executing
the yarn DB main Create, and it will create
all our tables. Now we need to
create a new user. This is why I am jumping
here inside registered tab. Here is our user, username Fu, password, email. I'm hitting here sand. And as you can see, our
new user is registered. Now we must copy a token because this is the most
important part files. Now we can jump in and create article and inside
header provide a new token because result
this token we can't really create our article is you
can see the body is fine. Here we have titled
body description and here is biography,
where hidden sand. And we've got our new article, as you can see now we have
here author with id one, and this is exactly our
user was username full. And this means that we
can jump directly inside our new request articles and
provide here Ortho form. Let's hit Send. As you can see now we're not getting
the empty array, but a single article
that we created, which actually means we had
the problem with the data because the data was stale
and not without request. And actually our code that we wrote for query
author is working. As you can see here, we're
finding a single author. And of course our
username is unique. And here we're adding to our request to add new
condition with our author. Actually there is one
more filter favorited, But we will implement it
later in a separate video. Just because we didn't implement logic was like and
dislike and articles. And this is really
related to that logic. As you can see,
Create Query Builder, Israeli low-level tool,
but don't use it always. But if we really need to tuna
or request, for example, work was query parameters, then this is the
thing to know and go.
30. Liking articles: In this video, we will talk about like and
dislike an articles. This is a topic for many-to-many association inside dipole RAM. So as you can see here, I opened our specification and we have to
request, first of all, we can favorite an
article and this is a post request to slash
API slash articles. Then we have a unique slug. This is our unique part. And then we have slash favorite, this URL we're using
to like an article. As you can see here,
our authentication is required because
we need to build relation between our user and an article and obviously
not logged in. User can't like the article. This request must return a
normal article as always, and no additional
parameters required. We also have the same request but unfavorite
article or dislike. We have here a delete on slushy
Pi article slug favorite. So actually the request is exactly the same
but it is delete. And also here authentication is required and adverse loop we can dislike our article on Lubin were
previously liked it. This is exactly what
we want to implement. The question is how? Because the main question is
how we will store this data. Just to remind you here that the front end of
our application, and as you can see,
I'm logged in. This actually means
that here are some posts that are liked by me. I can hit here like button. And in this moment we're
sending this like requests. So favorite article. I can also dislike that article and in this case we
will dislike it. So the request is the delete. The question is how we will
store it inside database. The main point is that we
have now two entities, article and use it. And actually several users can like the same article
because for example, two different people created two different accounts and
liked the same article. Which really means
we can't store this information inside
a single article. At least it's not like that
in relational databases. And of course we have the
same relation but vice versa. It means that this specific
user has the array of articles that he liked and
we can always get them. So normally we're using for this many-to-many
association here to the documentation of many-to-many relation
insight type RM. As you can see here,
many-to-many relation is when a can contain multiple instances of B and B can contain multiple
instances of a. This is exactly our case. We have article and user, and you can have several users that favorited the article. And you can have
several articles that are favorited by user. Let's check how we're
implementing it. For example, here in
the official example, we have a category and
we have a question. As you can see here, the question can have
multiple categories, and each category can
have multiple questions. The main idea, as you can
see here, inside entity, we're not writing anything
inside category itself. We're writing these three
lines inside our question. So as you can see here, we're right in many-to-many, and here is our category. So this is our relation
between question and category. Then we're writing the
decorator join table. This is extremely important. Here is categories,
category, array, which actually means from
the question we can write dot categories and
get the array of categories where this question belongs or from the category
we can do vice versa. As you can see
from the entities, everything is looking symbol, but here is how it looks
inside Postgres for example, here's our category table here we simply have ID and name. We don't store any
information here. Here is our question
and we don't store any additional information
here also, we have here id, title and text, but typo or RAM automatically when we're
writing these three lines, creates for us additional table. This table is
question categories. Category. This means that this
is the relation between these two tables. This is why here we have
questionnaire and category. Here we're writing, okay, we have a relation between a single question and
this specific category, which means here we have ID one for example, here is a D2. Then we always know, okay, if we are talking
about question, we can get all categories in this table where we have
this question a deep, then get all category
IDs automatically. This all is working
out of the box. But just for you to know this many-to-many relation
you have in every ORM, because this is super
popular and muted. And we will do exactly the same with liking and disliking. So first of all, for this, I want to jump inside
our user entity because exactly here we will write
our many-to-many relation. Let's write here exactly how it was written in
the documentation. So here we have many-to-many, and here we have a function
where we're returning our article entity here that the relation between a
user and an article. Now here we have joined. Table decorator. And after this where,
for example, favorites. So this will be our property. And later we can write user dot favorites to get
all favorited articles. And we know that this is
our article entity array. This is all that we must try. The next step is to
create migration. So we're jumping here
inside console and right and yarn db create here, for example, at relations
between article and use it. And we already have this
relation because this is how we named it when
we made one-to-many. But here we have favorites. So let's name it
favorite somewhere. For example, add favorites. Relations between
article and user. I'm hidden here enter
and as you can see, where have you migration? Let's check the sound. Here is our migrations and
here is our long, long name. As you can see here,
the most important part for us is that type program created for us new table
users, favorite articles. So this is the
normal name when we have a many-to-many
relationship. Here we have users table and articles table, and
here's favorites. This is the name
of our property. This is the most
important part for us. Now let's jump and said
console and dry it yarn db migrate to
migrate our database. Now let's check if our
table was created. So I'm champion inside PSQL
and right in here, D team. As you can see, these are
our list of tables and this is our new table
users favorite articles. Now we can start here all information about
like in our articles. The next step is to create additional methods to like
and dislike our articles. And this is related
to our articles, as you can see here. This is why we're writing it
inside article controller. Here on the bottom, let's implement this function. And by the way, as
you can see here, I have a warning, a way it has no effect
here because actually our articles service built article response doesn't need an await. It doesn't break anything, but we should not write it here. But this was from
the previous video. Here we have our post because
we are like in the article, and here is our URL Slug slash favorite and y like this
because as you can see here, our articles prefix is on the top of our controller,
as you can see here. Now here we simply specify
post for slug favorite. Now we also need
to use AAC world because it is only
for authorized users. This is why here we are, right, and you're squareds, and here is our house quarter
that we created previously. Now let's create
here, for example, add Article two favorites. Here inside we need two things. First of all, we need
NAD of the current user. In this case, we can
use it and store it. And secondly, we need
a slug of our article. And as you can see, this slug
we have here inside params. This is why we can use here, use a decorator and get
an ID of current user. Here is current user ID number. And we also want here, but RAM slog to get our slug. So here will be
slung as a string. Also, we know that we're returning here the
normal article, this is y here is normal article
response interface that would did previously. Now inside the mask create a new method inside our service. And this method must return
for us article, this is y, here is article and we're calling await this
article service. And let's create a new method
at Article two favorites. We're passing here slug
and current user ID. We know that this method will
return for us an article. This is why here
I can then return this article service and here is built article response and then sidewalk bias in her article. Now let's implement
this function. This is why I am jumping
and said service. And somewhere here on
the bottom, for example, after fine by Slug, Let's create a new method. Add article two favorites. Here we're getting slag, which is our unique ID, and now user ID,
this is a number. And we're getting
back as always, article entities
because we don't want to get here
normalized data. Now the question is how it will work and how
we need to save it. Actually, what we want to
do is to get current user. And then we can use here
user dot favorites. This is our array. Here we can just use push to put some data and then we
simply save this user. Then this favorites will be stored correctly in
additional table. So let's do this now. First of all, we want
here to get an article. This is why here I am getting
an article as previously, here is a weight find by slug and we're
passing inside slug. The second here is
to find our user. And you might ask why I didn't
pass the whole user here. The point is that here I
want to join the table. This is y. Here I'm writing a rate, this user's repository find one. And here we're
passing our user ID. This is totally fine, but we also want here as the
second parameter, an option. Here I'm providing relations and then saying here favorites. This actually means
that by default, when we're fetching single user, we don't get this relations
because we don't need to. But exactly in this
specific case, we want to get a user
with this relations. Now let's simply return here our article and check
what we have inside user. Here I will return our article. We didn't modify it. Here I will console
log the user so we can understand with
what we're working. Let's check this out. When I'm jumping
into the console, we have some errors. Here. We have a narrower
in article service, the return type of a sinc
function must be a promise. And in our case
it's not a promise. Here I forgot to
write what promise? This is super important. So here we have a promise
of article entity. Let's save this and check
this out once again. As you can see here,
now it is working. Let's jump to Postman. And here we have
in your URL slash, articles slash, and here
should be our Slug. Let's take some slug
from. Our answer. Here will be the slug and
then we have here favorite. Let's check the request slash, api slash articles slash
slash, slash favorite. This is exactly it. And here we have a post request and we should
not provide here any body. This really doesn't matter. Here. I want to save this request
and it will be like article. And we're saving it inside
our nest years collection. Let's hit Send. As you can see, we're getting back
their articles, so no errors here. And let's check what
we have in console. As you can see here,
there's our user and the most important part
is this favorites array. And we are getting
here this array, and this is actually
the ray from the giant table because we
are not stored in favorites, inside user identity directly, but through additional table. Now here we can work with
favorites of the user. What do we want here? First of all, we
need to check if our user already favorites
is unethical or not. We can write here, for example, cons is not favorited. What we want to
check here is use a dot and here we
have favorites. Here we can check find index. So actually if index is
bigger than minus one, then we have this record there. This is why here I am checking, for example, article
in favorites. Here what I want to check
is article in favorites dot id equals our article ID. What does it mean? Well, looping through
our user favorites and here we're checking
if we have this ID. So actually every single
article in favorites. And as you can see, this is an article entity
has NAD and we're comparing it with our ID that we found here
with this line. Here actually, as you can see, we're getting back a number. This is not what we want. We want to get here a Boolean and this find index always
return us a number. This is why here I want to
compare it with minus one. In this case, if our find
index returns minus one, this means that the
article is not favorited. So actually if we're making this request and the article
is already favorited, we just don't care
and will return back an article because we don't
need to change anything. But if it's not favorited, then we do our logic. This is why here I
will simply write IV. Article is not favorited. Then we must do
something. Though. Logic yeast, for
example, like this. First of all, we want to push an article inside
user favorites. Here we simply write Bush
article and we don't care, we should not manage
ideas and so on. Typer room does everything fast. So actually this will
correctly add in specific table new relations between user and the article. But for us it is
looking really easy. We simply push an article
insight favorites. The next steps that
we should not forget is to change favorites count. Just to remind you,
inside article, inside article entity, we have here a property
favorites count. This is the counter that returns how many people
liked this article. Actually every single time when anybody likes this article, we must increase it. This is where here we're
writing an article, DOD favorites count plus, plus. And this will
simply increase it. Now we just need to save
our user and our article. Here I'm saving First the user. This is why a way this user repository save and we're throwing
inside our user. And secondly, the same
for the article here, this article repository save. And we're passing
here an article. What we're doing
here once again, first of all, we are getting
this slug end user ID. This is the specific
information from the request. Now here we're finding
an article and our user with relations and relations is of
course important. Here we have is not favorited which
returns true or false, depending if we have the
nautical inside favorites array. Now here we're checking if
our article is not favorited, then we're pushing it inside, increasing the counter
and saving both of them. You can see by using oil RAM, our code is super
easy and super clean because we're not working
with tables directly. Now let's check if it's working. I'm jumping here, as
you can see, no errors. Let's test this. Now. I am inside Postman
and I'm heat and send. As you can see now we're
getting back the article, but we have here
favorites count one, which actually means that
we modified our article. This means that we
saved our relation. Let's check this out for the
same champion inside PSQL. Here Let's write
select star from users favorites articles
to get all records of it. And as you can see here, we have only a single record. And here we have a
relation between users ID and articles AD. We now know that
this user will say D1 liked the article with A11. And actually this means that our liking of the articles is implemented correctly
because we're successfully created
this relation, recreated emigration, and now we saved everything
inside database.
31. Disliking articles: In previous video,
we successfully implemented lichen
of the articles. In this video we will
implement disliking, which will be exactly
the same logic. So let's check this out. Just to remind you here
we have to request favorite article and unfavorite. Favorite Walter, the
implemented to unfavorite, we have the same
URL, but the delete. This is why I will jump
inside article controller. Here I have slug favorite. What I want to do
here is copy-pasted completely because it
will be exactly the same. The real difference is
here we have a delete. This is it because we have here slug favorite user acquired. Here we want to name
it, for example, delete article from favorites. And here we have user ID, which is our current user. Here we have a slug
from the parameter back where given article
response interface. So everything stays the same, but also need here
and new method. So let's name it, delete article from favorites. And inside we're passing
slug and current ED. And here is built
articles response. As you can see, this is
super similar and just another method and of
course delete here. Now let's implement this method inside our articles service. Here I am inside at Article two favorites and
let's create now a new method, delete article from favorites. And we're getting here
like in previous method. First of all, slag,
this is strain, and secondly, current user
ID, this is a number. Back we're getting as always
promise of article entity. Now what we want to do inside
is exactly like previously, we can actually copy
paste all this code. Because first of all, we
want to get an article, secondly user with the relation. And third, we want to know if article is favorited or not. This is why I will simply
copy paste everything here. So here we are
getting an article. Here is our user
actually here we named it user ID and
not current user ID. Let's do the same
here. It's a user ID. And then here is not favorited. But they actually here I want
to change code a little bit because we need here index to remove the item from the array. Because for us we have the array with items
like articles, and we want to remove here
an article if we have it. This is why actually want
to save in this property not is not favorited
But article index. And then here we don't need this Boolean
comparison because we really want to get
back article index. So actually here we either get a normal index or minus one. And minus one means that
this article is not there. This is why here we
want to check if article index bigger or equal 0, and this means that
our article is there. The next step here inside we want to remove article
from favorites. This is why we're right
in here user favorites. And here I can use splice, just modify our array directly. What they want to remove here
is article index comma one. I want to remove a single
element on this index and this modified directly user dot favorite because this
is a mutation function. After this, we want to
decrease our counter. Here we have article
dot favorites count, and here we want minus minus. So we're decreasing our counter. And of course the
question is here, if we're not decreasing
it to less than 0, and actually here we have
a check for article index. This means that it can't
be realist smaller than 0. Now we just want to save both user and an article
like we did previously. This is y here, user
repository save and inside this user here
we're saving our article. Here there's articles,
repositories, save article. Just to remind you how everything is working,
we are getting, first of all an
article and secondly, our user was favorite. Then we're finding
article index. This will either be minus one or normal index
0 and something bigger. In this case, we know that
our article is there. This is why we can dislike it. Because if our
article is not there, we should not do
anything at all. Now inside we have this logic. If article index is
bigger or equal 0, so we have an index, then we're using Splice to remove the article
from the array, and then we decrease
the counter. And obviously saving
these two records. And of course at the end we
must return here an article. So here I am returning
the article. And if we didn't modify it, then we simply return the
same article and would do it. Then here we change to the
favorites count and saved it. Let's check this out. We don't have any errors here. Let's jump to Postman. Here is our article will
know that this is favorite. This is where here I'm using delete and they want
to save the request. So here will be, for
example, this like article. Let's save this inside next year's collection so
we can reuse it later. And we don't need
actually anybody. It doesn't matter if I
provide here something, we simply ignore it. Here I'm hitting sand. As you can see, we
got back our article. And now favorites count is 0 because we're
disliked the article. And this actually means
that in our table, we don't have any records. Let's check this out. I will jump inside
PSQL and right here, select star from our
users favorite articles. As you can see here, we have
no 0 roles because they pour RAM successfully removed
this single relation. This means that our dislike
is working correctly. Which means we successfully implemented like and
dislike an article. But here are some things
that they want to improve. First of all, just to remind you inside our list of articles. So requests literate
past lush articles, we didn't implement previously
this filter for favorited. And actually this filter is
needed when we want to find all articles that are
favorited by specific user. This is why now I want to
implement this functionality. Let's jump inside our service
and it was feed on the top. Here I will go to the top. This was find all. Just to remind you, here we had different queries
like Query Tag, query author, and now we must
implement query favorited. This is why here
I am write an IV, we have query favorited. Then we want to do some magic. And first of all, we want
to find our user with relations because
only in this case we can find all
favorited articles. So here I have an
author of this article, and here we're using a weight
of this user repository. And here we have
find one because we wanted to find
just a single user. And then side I am
passing username. And here will be
query dot favorited, because this is exactly
the unique username that we passed here. Here we found our user. And the most important
part that here we want to set some options. Here what we want to do
is pass our relations. And here we're saying favorites. In this case, we will
not get on where a user, but a user with China
table of favorites. Now let's console
log what we have. Here. I will simply console
log our author. We can debug it and
see what it is about. First of all, let's
jump in web server, as you can see, no errors here. Then I will jump to Postman and click on
getting articles. So this is the
request get articles. I am hidden sand, as you can see this as an
array of our articles. Now, we want to write here
question mark favorited, and here will be our user. Actually, first of all, we need to favorite some
article by some user. We have only user foo here. We can check this out. I'm hitting sand.
As you can see, we're getting our response. But for us interested
in is this console log. As you can see here we
are getting the author. This is our user entity, and here this favorites. And it is empty
because we didn't like any articles to make
it easier to debug. Let's like some article. This is why here I can't use
our requests like article. Here we have some
article and we'll make an favorite for
our currentUser. I'm hitting here sand
and as you can see here, there's favorites, count one. Now I'm champion bag inside our articles response
with favorited full. I'm hitting sand and
looking in the console. And as you can see now, we have this nice
array favorites with article entity inside. This means actually
that we will have here the array of
article entities. We can write some
code regarding it. So actually what we want to do here is to add one
more condition. And we want to check that every single article that
were returned an int, the response is inside
this favorites array. This is how we can do it. What we want to do
here is first of all, to get the IDs which
are favorited. This is why here I am
right and const IDs, for example, were taken
off the DOD favorites. And here we're making just map. We are getting each element
and here is element dot ID. In this case, this
is an array of numbers which are IDs of
our article entities. Here we got our ADCs, which is array of numbers. We can do now query
builder dot n. And here is one more condition. Here I want to write
articles stored or so ID in, and here I am right and
round brackets then colon dot, dot, dot IDs. And here I will give as a second parameter
object with ideas. If you will check the
documentation of Topo Program, sometimes we want to
check that some property, for example, or society
is inside the array. This is how we are writing it, we're writing it within. And this strange construction. And actually in here, it means that this construction
and this AD's and ideas that we're providing
here is the array. This is why we're checking
that this idea of the article is inside this
array that we got here. And if it is inside, then we will return it. But here is one small
problem that you will get if you will
write code like this. And actually this
is the problem or a bag of type RM itself. You can't really make this request if you're
a DES is empty. This means that we must
wrap this logic inside some if condition and check
if this is not empty. In other case it
will be just broken. This is why here I will write
this length bigger than 0. Then I want to do this request. In other case, I don't
want to attach anything. But actually this
logic is not correct. This just means that
if we have lands, so if we have some
favorited articles, then we will apply this logic. This is completely fine, but the problem is if we
don't have any ideas, in this case,
normally we wanted to return for this author,
the empty array. But from our logic now, if we are not going
inside this array, then we simply return all our normal articles without filtering
them by favorited. This is why here we really
want to say that we don't need to return anything if
we're not inside this IV. Here, I want to say else. And what we want to say
here is Query Builder and where here we want to write something that
will never happen. In this case, we will get
back the empty array. This is why here I
am simpler, right, in that one equals 0, this is always false. This is why if we have
ids which is empty, then this line will return
for us an empty array. Here I am jumping into web
server, no arrows here. Let's open Postman and hit full. As you can see
here, we're getting just a single article because this is the online article which has favorited by user foo. Now the question
if it will work, if we will dislike the article, so we have 0 favorited articles. For this, I will hit dislike
article and click Send. So we have no 0 records. Now let's try again. I'm clicking on articles
and here I am hitting sand. As you can see, this is exactly what I was talking about here. We're getting a 0 articles. But if we will remove
this logic, this else, then we will simply give back
all articles that we have. And this is not the
correct behavior. Successfully implemented our
query parameter favorited. But here is one more small
problem that we have. Actually, if we will just scroll here and click on
multiple articles, as you can see in
every single article we have this property favorited. And the problem is that we
have this property everywhere, like in every single request, we have this favorited field, which actually means that in every single request
when need to write some logic to attach
this favorited property here, because actually inside
our article entity, we don't have such
property and we're not getting it directly
from the database, which means we
must calculate it. And they want to show
you on the example of our articles request
how we can do it. This is really quite easy. We're not doing anything here. I will just remove
the console log. But here on the
bottom, for example, after all our
offsets and limits, before we are getting
our articles, we can get the array of favorited and then
just normalize it. The main point is this favorited property is
only for current users, because actually this is
set only for current user. If you are not logging in that it will simply be always false. This is why here I want
to create a property with lead favorite ideas. And here we have an
array of our numbers. And by default, I will
write here an empty array. Here we will write the array of ideas that are current
user is favorited. Now I want to check if we have current user ID
and if we have it, then I want to get here current user with
favourite property. This is why here we are
getting our current user with evade this user
repository, find one. Here we have our
current user ID, and then we have
the relation inside relations as previously
were, right in favorites. Now here we've got current
user ID with favorites, non-book want to get favorite ideas like
we did previously. This is why here we have
current user dot favorites. Here we have map and
for example, favorite. Here I am returning
favorite dot ID. In this case we are getting
the array of numbers, which is the array of like
articles of current user. What does it mean? Here we have favorited these as empty array and this we have
also for not logged in user. Now, if we're logged in, we always want to know if we
like some articles or not. So here we're
overriding this array. With array of liked articles. Now here when we are
getting our articles, we can add an
additional property to every single article afterward getting them from our database. Here we can create
after articles, articles with favorited. And here I want to map through our articles and here I have each article and they want
insight to find the favorited. Here will be favorited. I'm just doing favorite ideas. This is what we created previously and
we're checking here includes to check if we have
this ID inside the array. Here I'm checking
article dot ID. Actually we simply looping
through all our articles. And for each article we're checking if it is
favorited or not. And after this, I want to merge our article with
property favorited. If we're not logged in, then this favorite
to that property will be everywhere false. And before I logged in, then we will check it. And as you can see here, now, this is not the article entity. This is the array
with all fields of our article entity plus
favorited Boolean. This is extremely important
because this is what we want to return back
inside our request. Now here instead of articles, I want to return
articles with favorited. Here is a really
super strange thing because as you can see here
previously inside articles, we have an array
of article entity. This is where everything
is working out of the box. But as you can see here, it's not article and it anymore, this is just an object
because TypeScript just took all properties
from our article entity. But here we're getting
a narrow actually that property update
timestamp is missing. The question is what
is update timestamp and actually went bad champion
inside article entity, we have here update
timestamp function. And actually
previously it worked because we were
returning here directly, article, entity and
TypeScript didn't scream. But in our case now this is
not article entity anymore. This is why this
function is not there. This actually means that
we must use our types a little bit in the same way
like we did with the user. And just to remind
you, here we have the user and we had types. And here we created
user type where we're unmuted from user
entity hashed password. And now we must do exactly the
same for our article type. This is why I will copy
this code and jump inside our article types. And we can create here
article type dot ts. I will jump inside here. We don't need this input
and they will rename this type user types to
our type article type. Now here I want to use Amit article entity and they want to admit here
this function. And as you can see, the name of this function was
update timestamp. So let's write it here. Update timestamp. This is now article type, and now inside our
response of articles responds instead of
array of article entity, we can use article type. So let's import it and
remove here article entity. In this case, now
we're returning here. First of all, articles
count as a number, and secondly, article
is article type. And actually article
type is simply a political entity without
update timestamp function. Let's check if it's working
now, as you can see, I'm jumping here and we
don't have any errors because here we're returning
article type array. And in this case this part is
exactly article type array. Now let's check if it's working. So here I am jumping
inside the web server. We don't have any errors here. And now we can open up Postman and make our request
for articles. And it doesn't even
matter if we're using here favorited on NADH, we will always get this property
which will be favorited. Let's check this out. I'm hitting sand and now we're getting here and new
property favorited, which is false or true. And obviously for us
this property favorited is false because we
dislike the article. So if we want to check it, then we need to
like article again. Here I'm hitting sand
to like the article. I'm jumping inside our
articles, hidden sand. And here we're
getting our favourite through because this logic
is working correctly. And here we found
currentUser AT, then we've got
favorite eighties. And here we mapped our articles with favorited
for every article.
32. Seeding the database: We're almost finished
our module article. There is still one more
method to implement, but we can't really do it
now because it is related to profiles and
following unfollowing the users that would
don't implement yet. This is why in this video, I want to show you
something important for configuring your
nest JS application. I'm talking about
seed in your data. What is it about? Normally we're doing a lot of drop databases and migrations, which actually means
that every single time when we're
dropping the database, we're dropping all
records from it. This is not comfortable because every single time after
migrations and dropping, I must create users by hands, may be articles, tags, posts, whatever I need
to start developing. This is not comfortable and
this is just useless work. This is why in normal
frameworks you have something which is called
seed in the database. You have some
predefined data and you just throw them
inside the database. Unfortunately, inside nastiest, there is no such functionality, which means we must
implement it on our own, but this is not that
difficult and in this video you will
learn how to do it. So actually the easiest
way to do it is just to create a separate migration which will be used
for citizen data. Why is that? Because they actually went to where column migration command, it is just execute in some
file with logic inside. Here we have, for example, credit runner and
everything is good to go. But of course, we don't
want to pack our migration for seeding here
inside our migrations. First of all, because we
are calling our migration's not on development but
also on production. This is why we want here
additional folder like seeds, and we will have our
seed in data there. And also we need an additional
command to seed our data. This is why the first
step here will be to create additional config
for Syrian our data. Here I will create IRM
seed config dot ts. This you can see we have
already ORM conflict. Yes, I will open it
here on the right. And as you can see, this is the whole conflict that we have. We can reuse almost
everything from here. What we really don't need is this Migrations folder and
Cl live migration directory. The main idea is
actually that we will try it in our seat Conflict
Migrations folder, but it will be seats. This is what we want to do. Here. We can write const, and here will be config. This is just an object. What we want to do now here, we want to use a conflict. We can import this
or REM config. This is export defaults, so without brackets just
to have them config from. And here we will have our
app slash or a ram conflict, which means we fully take all these properties
from the config. Then we spread them here, and then we override
several of them, which means we
should not type here the whole conflict
for Postgres for database user with simpler
override several properties. Here I want to write
first of all, migrations. Here will be source
seeds slash star dot ds. As you can see previously
here we had our migrations, which on our normal migrations, but here we will take them
from the seeds folder. This is the only difference. Now here we must specify CLI and inside we will have
our migrations directory. Here will be source slash seed. Actually this is it, This is our full configuration. Now I want to export defaulted here or a ram seat conflict. Actually these are
all these fields with overwritten migrations
and migration directory. Our next step is to create this folder and I'll
migration inside. Here. I want to create for the seeds and
inside a migration. So here I'm creating a new
file and important thing that this file mustard
with some timestamp. This is why here I have
just a random timestamp. You can use this or just copy the timestamp from
any of our migration. And as you can see here, the name is seed db.json. Actually the name
here doesn't matter. And we will have a
single migration where inside we will
throw off our code. And actually what
they wanted to do. I want to jump in
migrations, for example, create tags and copy paste
everything from here, and just paste here. So actually we will have
almost the same code. But first of all, I want
to change the class. So here we have Cdb
and then this AD, it doesn't really matter. It should be a unique class and it implements
migration interface. This is fine. We'll
also need another name. So it is the same name
like here inside class. And now we have up and down. The point is that we don't
need anything in down at all because we simply
won't implemented for us, seeding is just a process
that we don't want to revert. This is why empty
function down here. Now here inside up, we want to write some R code that will insert our
records to the database. So what we can do here, remove everything
inside these brackets and write insert into, for example, we want to
create some default tags. This is why here
I am saying tags. For tags, we have only a name. Now here we're
writing values and here we will have
several values. For example here
whereby sin dragons. And actually this
is how we normally make insert inside the database. And of course I
missed here letter t. But the point is that we can
also insert several records here after values and
then round brackets. We can put comma and then
one more round brackets. This means that it will
insert several of them. For example, here
we insert dragons, then we insert coffee. For example, the last
one will be at Nest GIS. In this case, we're
uncertain in our seed file, three default popular texts. Now let's just test if
this work in at all. So what we need to do is jump
inside of a package JSON. And here I want to create a
new command and it will be, for example, db seed. Then what I want to do here
is exactly what we have here. Why? Because as you can see
here in topos around with specified conflict source
or a ram conflict. Here we must specify
different conflict. Actually, I will
copy everything from type RM based here and then change this source
or a ram config to source or a ram
seed config dot ts. And now at the end, I can write migration run because we don't
want really to save just the command
type RM would want to do here migration run
how we're normally doing. But for the seats folder, which actually means for
typos and we're saying, okay, seeds is now
our migration folder. This is why tapeworm will make great the single
seed file files. Now let's check this out. I am jumping into the console, toluene it yarn db seed. And as you can see in this case, it should do one seed. As you can see here,
we have the message one migrations were found
in the source code. And here is our code
with insert into tag, and this is the name. So as you can see, it
was done successfully. This is why we can jump
inside pH scale and write select star from
tags to get old tags. And as you can see here, we're getting three tags
that we created inside seed. Our workflow is like this. Normally we're right in
the yarn to be dropped. So we're dropping
the full database. If we need to change some
data or restart everything, then we're right in the yarn db migrate to make create the
tables and create them. Last button, at least we're
right in the yarn db seed, and it will generate
default seed data for us. The most important
point here to remember that you can run
migrations only ones, because as you can see here, this line will create the
record inside migration stable. And this means that a
country right here, young DBC it again because
it won't do anything, because this migration
is already there. If we want to run
seed command again, we need first of all to
drop our tables completely. As you can see, everything
is working and we successfully created
our seat command. But now I really want
to change it a little bit because just tags
is not enough for us. This is why I am
jumping here and I want to insert maybe
also articles, of course, a user. This is why here we can write
a weight and run a query. And here we want to
insert the user, this is y here we're
right and insert in turn. And here we will
have users table, and now here are fields
that we want to insert. And first of all, it
will be username, then email and password. Just to remind you our
password is hashed. This means that what we can do, we can jump here in the
console and write select star from users and copy
paste all this code, as you can see here
now we don't have any user because we
dropped our database. To test this, we need
to hit on register. Here is our registered request. As you can see, username is
full and password is 123. We are sending the request. This is the answer. And now we can copy, for example, this
password from the answer. Because this is what we want to store inside citizen data. Here we must provide our values and here we
will have first of all, full, this is our username. Then we have full at gmail.com. And last one will be password, and this is our hashed
password that I cooperate. And now we can make here
a comment for future, so we don't forget
our password is 123. The last thing that I
want to create here is a single article for testing. This is why here I will write a weight query, ironic query. And here I want inside to
create a query for our article. This is y. Here will be insert
into articles. And here we have lots of fields. We have here slug, title, description, body
and triglycerides. But actually tick
list has a problem. We're controller right here tick list because it
will be lowercase for Postgres and it won't work for us because
inside our entity here, inside article, article, entity, We have here Tag
List as camelcase. And actually the correct
way to work with it is to rub it in quotes like
this in double-quotes. In this case, this will be just a string and this
is fine to use it as a column like this because our column is tagged
list with big L. In other case, we can't really
create the correct column. And also we have here also, I did was exactly the same
problem it does CamelCase. This is why we're putting
it inside double quotes. Now here are our values here. And just to remind you
were right and all values in single quotes. First of all, we have our slug. So here we can write
first the article. Now then we have here the title. So let's name it first article. Then we have our description. So here will be first
article description. Then we have a body. So first article body, then we have tag list, and in this case
we're passing in size string because
just to remind you, we're not saving arrays
inside our column, we have the string
deified column. This is why here
we have a string, for example, coffee,
coma, dragons. And it will work correctly
with nice chairs. And last but not
least, of course, here is the AD of our user. Here we are writing one
because here we created the first user and for the
first user we have index1. Now let's paste here
one more articles. So we have several of them. So here we have second article, the name is second article, the description is second
article description. Then we have the body,
second article body. And then we have, for example, coffee and dragons. This is fine and user ID is one, which means we're
successfully prepared all our runners for seed file. Now what we need to do is jump inside console and
try once again. So first of all, I will do drop to remove completely
our database. Then when it dried yarn db migrate to apply our migrations. And the last one is of course, yarn db seed to add our seed
data inside the database. As you can see, our sheet
command has an error. And here you can see the query
where this error happened. So insert into Users has
some problem inside. So let's check this out. Here. I already can
see our problem, as you can see after our email, I put coma twice and this
is of course not correct. Here we simply need common ones. Now we must do everything
once again, first of all, young dB drop then may
create and then seed. As you can see now, we
don't have any errors and all our inserts were
done correctly. This is why we can jump inside
of a pH scale and write, for example, select
star from users. And as you can see,
we already have a user which is successful at
registered and it is there, which actually means
we should not every single time register a user. We simply can use the user
that were already created. And let's check this out. We can simply make login. And here is our full
at gmail.com and password 123 where hidden
sand and as you can see, we return the user
because our data was successfully seated with
our seed migration.
33. Getting a profile: In this video, we're
starting in your section, and this is working
with profiles. And let's check what we have. Here. I am inside specification
and as you can see, we have a get profiles request. This is slushy pie
slash profiles, and here is a username which is a dynamic and unique part. Here as you can see,
authentication is optional and it must
return a profile. What is profile? This is the new response. We're inside we have
a profile property, and inside we have
username