Welcome to this video course on
minimal API with dotnet. Seven. By the end of the course, you
will be able to build well constructed minimal API
endpoints Brueggen Patel developed this course, he is an
experienced and popular course creator and developer. Let's get
started. Hey, guys, and welcome to dotnet
mastery. My name is broken. And I will be your instructor for
this course on minimal APA. APA has been there since a very long
time. But Microsoft has launched something new with API, which
are minimal API. If you are a dotnet developer, your first
reaction would be, why would I need minimal API when I'm
perfectly happy with the standard API that are there. On
top of that minimal API, as the name suggests, offer less
features as compared to a traditional API. And in this
course, we will answer all of those questions, as we will
explore all the benefits minimal API brings to the table. We have
a lot to cover in this course. But there are some prerequisites
that you should know, you should be able to follow along, as long
as you have about three to six months of experience with C
sharp. That being said, let me walk you through on what we will
cover in this course, and explore the new world of minimal
API. Let's take a look at what will be all the topics that will
be covered in this course. First question that we will answer is
why minimal API? What is the reason behind the evolution?
Does it bring any benefits as compared to the API? And what is
the different structure when it comes to an API? Once we answer
that basic question, we will understand the basic
fundamentals of minimal API's, what files are there, and what
is different as compared to API. Then we will be building
endpoints with our API. And we will implement custom
validations. And minimal API. Minimal API does not support the
model state validations that are there in API. So we will see how
to validate some things and minimal API, we will learn more
about dependency injection, we will inject auto mapper and we
will see how to map DTOs in our application. And then we will
perform crud operation with minimal API. So you can see
there's a lot that we have to cover. Let me get started with
all of that from the next video. The main question that comes
around all the developers, especially dotnet developers, is
why minimal API, we had a perfectly functional API that
has been there. And we love that with the controllers, attributes
and all the features that are built in. If that is working
perfectly, why is Microsoft taking some bits and pieces out
of that API, and giving us a very empty template? Which is
something like a minimal API? What could be the benefits of
having a minimal API? To answer that? Let us consider the
scenario. If a developer is coming from a non dotnet
background, for example, no GS, in that case, they might not be
aware of what is your controller, what are naming
conventions for controller, and learning all of that would
require some understanding of dotnet. But their main focus is
to get the EPA up and running quickly, without learning all
the fundamentals of dotnet. Programming. That is one of the
reason behind development of minimal API, we want to have the
minimal code that is needed for API, rather than adding
controllers. Because if you think about that, when we have
to build an API, in other programming languages, or even
in dotnet controller is not something that is always needed.
It has been there because previously we had MVC, and we
had controllers. So Microsoft thought about unifying both of
them. And that is the idea behind controllers. With minimal
API's, we do not have the controller. We keep everything
simple and straightforward in a class file. Now, when we learn
minimal API, everything will typically be in a program.cs
class file. But then developers might think that my code will
look ugly. If I have 50 end points and all of them are in
one file. Do not worry. We can of course separate them out in
different files as well. But me point here is we don't need a
controller. Now since we are not adding extra features like
controllers and other overhead, which is not always needed for
an API, we gain performance improvement, which takes higher
priority in some situations. So if we are keeping things
minimal, then the performance of our API will increase. Microsoft
is investing time in minimal API. And it is adding more and
more features. Like previously, there were no filters, but they
have added filters with minimal API in dark net, seven, and much
more. With all the new features being added minimal API are
gaining more and more attention, especially in scenarios like
microservices, where API are not that intensive. And efficiency
plays a critical role. With that overview, I'm sure you are
excited to learn minimal API, and what they have to offer,
what is the syntax, how we can perform crud endpoints and much
more. To get started, we need to create a project that will use
minimal API. So I will open Visual Studio 2022. And we will
hit Create a new project. In the templates here, we will search
for the regular API project. And we have the ASP dotnet core web
API using C sharp. Let me hit the next button here. And we
need to give a project name, project name, I will change that
to be magic biller underscore coupon API, we will change the
location where we want to save the project. And the solution
name, I will call that minimal API demo looks clear. Let me add
that. And we have more option. The framework here we will be
using dotnet seven authentication type, we will
keep that as none. But later on in the course, we will be adding
authentication and authorization configured for HTTPS looks good.
We do not want the darker support. But the main thing here
is use controllers, we have to uncheck that if they want to use
minimal API. Because if you keep this checked, then it will
create the regular API project with controllers. We do not want
that. So we will uncheck that. And that will create a minimal
API, we will enable the open API support. And lastly, we do not
want to use the top level statements, we can keep that as
unchecked. With that in place, let me hit the create button
with the default settings. And great our project is created
here. And we have our minimal APA right here. Before we go
through the files that we have and minimal API here, let me
create a regular API project back then we can compare and see
what is different. So in the solution here, we will add a new
project. And it will be an API project. I will conduct regular
API sample, let me add that we want to use the controller. So
make sure that that is checked. And we will hit the Create
button. Perfect that is created. Now that we have a minimal API
and a regular API project. Let me compare to see what is
different. You can see in minimum API project, we have
properties folder. Same thing is there in regular API. And there
it is just the launch settings dot JSON file that basically
tells that which port it should use. And it has a profile for
Kestrel as well, that stays the same. Because no matter if it's
a minimum API or a regular API, it still needs to run the
project on a URL. And outside of properties folder, we have App
Settings dot JSON, that is also constant input of the files. But
other than that, in minimal APA, there is just one file, which is
program.cs. Whereas in the regular API, we have
controllers, we have program.cs, and the weather forecast model
class as well. So going by the name minimal API has actually
minimal file, only program.cs. And that file has all the logic.
Now let me set the startup project as part of the project
here. And let's see if the output is any different. And great. We have both of them
up and running here. Let me add them side by side. and perfect.
We have both of them right here, we have the regular API. And
here we have the minimal API. From the look and feel, you can
see both of them looks the same. We have one endpoint weather
forecast that looks good in the swagger documentation, we try
that. and execute, everything is the same, we have the same
response. And everything looks the same. So from the look and
feel, or the Functionality wise, minimal API is not that
different. Now, of course, as we proceed with the course, that
will be some features that are not yet available in minimal
API's, or they are not planned to be added. But the base
functionality that we can see right out of the box looks the
same. But minimal API has only one file, the regular API has
controllers, program.cs and weather forecast. So that gives
you a good comparison between the files that are present in
minimal API as compared to the regular API project. Now, as a
prerequisite to this course, I hope that you have a basic CRUD
functionalities of what API is responsible for. If not, I have
a free course on YouTube that you can take to get familiar.
But here in the regular API, we have a controller endpoint, we
have the API controller, and we have the HTTP GET action method.
That will be the endpoint, which will be invoked. And here we
have this model weather forecast. That is right here
included, that is the regular API for you. But now that we
open the only file that is present in the minimal API,
which is program.cs. Now, if I switch the funds here, you will
notice that add controllers is not present in program.cs, after
minimal API. And that makes sense, because in minimal API,
we do not have any controllers, then the swagger endpoints, they
are present, because we want the swagger documentation with our
minimal API as well. After that, we have app dot build. And that
is the same where we are configuring the pipeline. We
have swagger documentation for development, we have HTTPS
redirect authorization, map controllers and run. But in
program.cs, we don't have much things. We have swagger, we have
the HTTPS redirect. And that's about it. We just have the app
dot run after that. So we do not have any authorization or map
controllers that are added by default. The main idea behind
minimal DPI is to keep things super simple. If you have the
requirement to add those, you can of course add them. Like in
a minimal API project. It is of course possible to add a regular
API with controllers if you want that. But that is not the main
purpose of a minimal API. It is there to keep things super
simple. So if I examine the program.cs, we just have apps
that run with HTTPS redirect and swagger in the request pipeline.
Now, the main question is, how will it work? Before we check
that, let me remove the regular API project that we added. I
only added that to compare the differences. So you get an idea.
We don't need that anymore. With that, we only have one file
here, which is program.cs. Open. And that looks good. Let's
continue from the next video. When we run the project here, we
notice that there is one endpoint, which is weather
forecast. But where is this endpoint, we do not have any
controllers or any other file. So basically, that endpoint will
be somewhere in program.cs. If you scroll down here, we have
the map get right here. That endpoint is mapping a get
request. And we have the route right here. When we expand that,
you can see there is a little code right here. And this
defines what needs to be returned back when this endpoint
is called with an HTTP get request. We also have written in
and with open API that we will come back to later on. But
basically, this is how mapping is done. And if any model
clauses are needed, in the default template, they are added
right here, this is a record and we have the summaries array
right here. So all the calculation on what should be
returned when the endpoint is invoked. It is right here in the
program.cs class file. Now that will bring up lots of question.
If you are coming from a regular API background, and do not
worry, we will answer them one by one. But in order to get
started, let me remove all the code that is added here for the
endpoint. We want to start clean here. So perfect. Now, our
program.cs only has the swagger endpoints here. Pipeline also
has the Swagger UI, HTTPS redirect. And that's it. No
controllers, no authorization, nothing else is present in our
project or pipeline right now. Like me run the project, we
should not see the endpoint that was there before. And we see no
operations defined in the spec. So we do not have any endpoints
in our API. And everything is clean right now. Let's continue
and add our first endpoint in the next video. The next section
that I have is all about the API basics. Like what is a request?
What is a response? What are HTTP verbs, and so on. Now,
these are the fundamentals of API. And it does not matter
whether it's an API or minimal API. So if you are aware of the
basic fundamentals, like POST, PUT, patch, delete, and what is
a request response with the API, feel free to skip this section,
and move on to the next section, where we will start the
programming. But if you want a refresher, let's do that. From
the next video. We have the big question, what
is an API, the definition for an API is Application Programming
Interface. But that is not explanatory. In simple words,
API is responsible for transmitting the data. Or
rather, it is a way for multiple applications to communicate with
each other. In today's technology driven world, we are
connected like never before. API is the critical engine behind
sharing information across multiple application, and
programming. APA is responsible for getting a request from the
client, and then sending a response back to the client
based on the request, and the request and response that will
be multiple of them. And it continues. So basically, if a
client is looking for some data, it would ask API by sending a
request. And then EPA would return back that data in form of
a response. The model that we see here is the website model.
What is different between that and an API, what makes an API
stand out is it is not just the web browser that can call an
API, many other application can invoke an API endpoint. So let's
say you have an API that can be consumed by a web application,
your mobile application, or Windows application, and much
more. Not only that, you can expose your API to other
clients. And we have more examples of that. But before we
go into those details, the example that we see here is
related to programming. Let me simplify that by going to a real
world scenario. Let's say we go to a restaurant, and we have
menu on the table. And after a lot of thinking, we finalize on
what to order, Chef is also ready to start cooking. But the
missing link here is to tell chef on what we want. That is
where server comes into the picture, which is basically like
an API server will be responsible for taking orders
from the table and telling chef on what needs to be prepared.
And that would basically resemble a request. Once the
food is ready, tensor work will pick that food and deliver that
back to the table, which will be a response. So here you can see
how server is acting like an API, where it is taking the
request and then it is delivering back the response
from our kitchen. Now, let me show you one real world
scenario, which many of you would have experienced without
realizing that it is driven by APA. Let's imagine we are going
on a vacation and we need to book tickets by an hotel
reservation, like myself, I'm sure you want the best deal out
there. But it will be a huge pain to go to every airline
website to see what is the price of that ticket for a specific
date. Right than that, you would prefer going to a website like
kayak.com, Expedia or Priceline, where they will display the
rates for multiple airlines. And you can filter the best deal
from their website. What happens in the backend on kayak.com is
American united and spirit would have exposed an API kayak.com
will be calling those API endpoints based on date, origin
and destination. And it will return all the response from the
individual website. Whatever response it returns from those
website that will display all kayak.com. So basically,
American United spirit and other airlines will have their own
API. And kayak will be calling those API endpoints to display
the connected information in one place. Same thing happens when
you compare hotel rates on Expedia, Priceline, or other
websites, where they get information from multiple
websites. So as you can see, API is the main superhero between
connected services. In today's world, we take the web for
granted. When we open a browser and we go to a web page, we just
expect it to open up and work. That is the default behavior.
But what goes under the cover is a black box. In reality, many
things happen between when you search for something on the
browser, and what you see on the screen. Once you hit an Enter
button. Let's talk about what happens when we make such a
request, we will consider an API in our scenario. For example,
when we go on a laptop and search for something on
google.com, or any other web page, it is going to make a
request to some remote server. Now this request is actually a
text document. So basically, it will send a text document to
Google server. And this document will contain three information.
First, it will have a word, which defines what is the action
that server has to take. Then we have headers, which have
information about the request itself. And finally, we have
content, which is an optional field. As an example, let's say
you want to create something on the server. So in that case, the
HTTP word will be post. And we will learn about this words in
just a minute. But when we have to create, we will be using
post. And that is what we have in HTTP worm. Inside header, we
might have information about the content length, that the content
here will be nine byte. And finally, we are sending magic
API as the content. Let's say that is a string that we want to
create. So all the data will be inserted content. Now, this is
just an example. But this gives you a brief idea of what will be
there in the text document. When the server gets this request, it
can either recognize that as something it can process, or it
might reject it, because something might not be valid
with the request. But in both cases, it will send a response
back to the client. And in that response, we will have three
items. Again, we will have a status code, header and content.
When client makes a request, server processes that and sends
back a response response is also a piece of data. You can think
about that as another text document. The status code here
basically defines the request that was made, was it
successful, or did it fail? Based on the different failure
scenarios or successful scenarios, we have different
status code. In our example, we did HTTP POST request. So it
might send a status code of 201, which stands for created we will
get to know the status code very soon. So do not worry. Right now
it says 201 created in the response status code, which
means I have created the resource that you have asked me
to. And I'm going to return you some data along with certain
content type we are saying that the data that I'm sending back
is of type text. And then in the actual content, let's say the
server is sending back magic API. When important thing that
you have to remember is server itself here is stateless.
Stateless basically means that server will not remember things.
And what I mean by attack, a server will be getting multiple
request. Once it processes that request and sends a response
back, it forgets about that request. Because if it was
remembering about all the request, then you can just
imagine on how massive the memory consumption will be. And
the disk will be overloaded with the data of all the requests
that it received. So always remember that server will be
stateless. Based on what we have seen, we have a request that is
originated from the client, and we have a response. The request
will have word header and content and response will have
status code, headers and content. In the next video, let
me dive a little bit more into what exactly is in request, what
is HTTP web headers, content. And similarly, in response, what
a status code headers and content. Let me do that. In the
next video. Let's understand the request
object that we have. First thing in the request object is work.
And these are HTTP words are action. They basically define
what is the action that needs to happen. If you are working with
some data, you might want to create, read, update or delete
that data. We have specific word, which defines what action
is needed for the request. Most common of the HTTP word is when
you want to fetch some resource or a web page, which basically
means that Hey, get me something from the server. So that
basically means fetching some data. And that is most common.
After that, we have post which is used to create or insert a
new resource. Whenever you want to add a new record or anything
on the server, you will be using the post request, then we have
put, which is used to update a resource that already exists on
the server. Sometimes we also use patch, which basically means
that please do not update the whole resource, I only want to
update a part of that resource. For example, if your object has
100 properties, and you only want to update one of those
properties, you will use batch in that case, put basically
contains the complete resource and patch works on one part of
the resource. Then we have delete, which is pretty obvious.
It basically delete the resource from the server that are more
HTTP verbs, but they are very rarely used. And typically, we
always play with the five that are most common. So that gives
you a brief idea of HTTP verb, and what action they are
responsible for. The next part in the request object is the
header. Headers are a set of name value pair that are
metadata about the request. First one you can see is the
content type that basically answers the question on what is
the content type of the request? Is it a binary data? Is it a
JSON file? Is it an XML file, or is it a plain file, then we have
content length, which basically defines the size of the content.
In request microdata, you might also have authorization,
sometimes request needs to be authenticated. In that case, the
authorization header will be populated with a bearer token or
whatever authentication you are using. We also have accept type,
which defines what kind of a request is acceptable, like
JSON, XML, and so on. And then there are literally hundreds of
headers. You can also define your own headers if they are
helpful in your situation. But headers basically have metadata
of the content and request. And finally, we have content. Con
content is an optional field. Here, we can pass the content
that the server will require to complete the request. It can be
a JSON object, which can later be deserialized by the server to
process the request. It can also be blobs that have to be created
or updated. If you are trying to retrieve a resource, then you
will be using HTTP get word. And get will never have the body
because we are requesting the API to return something. And the
API does not expect any data in the request. But if you're
posting or updating, then we might have to pass the object
that needs to be updated or created. That way the EPA can
extract that object from the content to process the request,
this is a brief overview of the request object. Typing said,
let's analyze the response that we get from the API in the next
video. In the last video, we saw the request object, which had
work headers and content. Now let's examine the response
object, which is basically once the request is received by the
server or API, it will process that it might be accepted, it
might be rejected, failure or success. Whatever it is, it will
return back a response. The first thing that we have in
response here is the status code. status code is simply a
number that represents on what was done on the server, and its
final result. But all the numbers that are returned have
been arranged in some brackets. And they are very critical, like
100 to 199, or informational. You will rarely see the 100
status code, but they do exist. Most common one that you will
see is 202 299. Any status code in that range basically means
that the request was completed successfully. 200 is most
common, where it says everything is okay. And everything is done
as requested. That next we have to work one, which means
created. If you are posting something, then you can return
it to someone that the resource was created on the server that
defines 201. Then we also have war for no content. This is more
common when we are updating something. Because when we
update a record, we just want the user or client to know that
the update was successful. And we do not want to pass the
updated record. In that case we will return to work for which
basically means no content. But as you can see, it is within the
success bracket. That means everything was successful, but
we do not have any content to return. Next bracket is 300 to
399, which are typically used when there is redirection
involved. After that we have 400 to 499, which relates to client
errors. What I mean by client error means that there is an
error in the request that was sent, you may not have included
a query string or some part of the URI does not exist. The
famous one that you would have seen on websites is 404, which
represent not found. So let's say you are accessing an
endpoint that does not exist. Like let's say you want to
retrieve something based on an ID, that Id does not exist. In
that case API might return back for or for that the resource
that you are looking for does not exist. We have 400 status
code, which stands for bad request, which means something
in the request was not as expected. And then finally, we
have status code within the bracket of 500 to 599. And these
are for internal server error, like the 500. Here is internal
server error, which means that errors have been encountered on
the server while processing. So basically, the request that was
sent to the server was a valid request. But when that request
was being processed by a server, let's say an exception was
thrown internally. And because of that, the server could not
process a valid request. So that time it will send a 500, which
means there was some error on the server side, and nothing was
wrong in the request. You can see status code plays a very
important role in the response object. Because based on the
status code, the client will be able to know if the request was
successful if it failed, and if it failed, what was the reasons?
So on the next we have headers in the response object as well.
And they contain metadata. But this time, they will have
metadata about the response object, like what is the content
type, what is the length of the response content, until when it
will be valid, and so on. Also, similar to the request object,
we have content in the response object as well. And that might
contain JSON result, it might contain blobs, HTML, whatever
the response server has to send, that will be in content. So
typically, if we have to compare request and response, both of
them will have headers and content, but the main thing that
differentiates them here is the word and status code. Request
has the word which defines what action needs to happen. And
response has the status code, which defines if the request was
processed successfully, if there were errors, and so on. headers
will be different for request and response. But typically
headers defined metadata, and content will have any content
that needs to be passed with either request or response. So I
hope this gives you a 10,000 feet overview about request and
response, and what is included in them. That being said, let's
continue from the next video. Now we know the basics about
HTTP worm. But let's take a look at some URL and get some
theoretical idea behind the HTTP worms. Most common HTTP worm is
a get request. Let's assume we have a table where we have a
list of all the coupons in our website. That table is pretty
simple. It will just have something like a coupon name,
what discount we get and some other details. But we want an
API endpoint if someone calls that it should retrieve all the
coupons and send it back. Now this is more like a read
request, because of that the HTTP worm will be get. And then
we have the API path, localhost 7001, whatever your domain is,
that's okay. But after that, let's assume we are giving that
a route of API and 10 coupon, we cannot have any other parameter
here. And this basically, the action we want is to get all the
coupons. So in the request party, we will not pass anything
here. But in the response that we will get from the API, it
will give us a list of all the coupons from our database. So
that is a get request. Now another type of cat request is
where we are passing an ID of the coupon. At that point, the
HTTP word is still cared for. Because there is an ID here, we
know that the user only wants one coupon request will not have
any body, but the response party will have the single coupon that
user wanted. Now, of course, if the ID is invalid, we will not
send any response party with the coupon. But if that is valid,
the response party will have a coupon. These two are basic
request in HTTP kit. But let's say if a user or admin wants to
create a new coupon code, in that case, our HTTP word for the
request will be post, and we will use the same URL. Now the
way it will differentiate between the first URL and this
one is the HTTP word will be different. If the word is posed,
the API will note that that means that we will be creating a
coupon. So API automatically differentiates between the verb
even if the URL are same. So for post, we will create a coupon.
And when we are creating a coupon, if someone sends a
request, we obviously need the details about that coupon. Like
on the website, someone will write the coupon name, what is
the discount they want, and then the admin will hit the Create
button. At that point in the request, we will get all the
coupon details that the API has to create. So API will create
that coupon when it receives the request. And in the response, it
could send the created coupon or a route to that created coupon.
Now, if everything here does not make sense, right now, do not
worry. I am just giving you a basic idea of API and its
action. Next action or HTTP word that we have is book and that is
to update any existing coupon. In the route here, when we are
updating, we can pass the ID of the coupon that we want to
update because of the HTTP port word and request we will require
the coupon details that have to be updated. And once the API
updates the coupon typically does not send any response like
the updated coupon. If you want however, you can send it but
that is not the typical route that is taken. And finally, we
have the Delete HTTP verb, where again we will pass the ID here.
Action we just need to delete that coupon. It does not have
any request body or a response. Based on the ID that is there in
the parameter. It will delete that coupon and return an okay
request. That means everything was completed successfully. So
what we have seen here is what will be in the request party, or
what we will get in response based on the HTTP verb, and
something in the URL, whether we require an ID, if we don't do
that, and so on. So this should give you a brief idea about what
each request or rather HTTP word is responsible for. Now, again,
this is just a rough idea. Once we start programming, everything
will start making much more sense. That being said, let me
continue from the next video. Let me add our first endpoint
right here. One thing that you should remember is all the
endpoints, we will have to configure that before the
pipeline ends. Because in a traditional API project, if you
remember, we were using something like f dot add
controller, and that was adding controller to the pipeline.
Here, we are not adding the controller, so all the endpoints
of your API that you want to add, you will have to add that
before app dot run. Right here, we will say app dot map. And you
saw before, we had something called as map cat that actually
maps or rather tells that this will be an HTTP GET action
method. If you examine the parameters, here, we have a
string with a pattern and a delegate handler, I can define
the route of this API. So we can say something called as hello
world. And watch that return. You can keep it simple. And we
can just return back hello, word like that. That will add an
endpoint in our minimal API. Let me run the project. Perfect. You
can see we have that route here. We can try that out. execute
that. And we have hello world. If you want to test that using
swagger, or it is an HTTP GET, we can directly paste that. And
we see the word right here. Perfect. You can see our
endpoint is working as expected, and how simple it was to add an
HTTP GET and point right here. Now, that would make you
curious. And now you will be like, can I have an HTTP POST
endpoint? Of course you can. We just have map post here. We can
call this Hello World, too. And we can return hello world to Now
typically, an extra day began, you will have something in from
body where you will be creating a record. But we are keeping
things super simple, right now. Let me run this and see if that
works. Perfect. We have the post here, write that out. We don't
need any parameters. And perfect, we get the response.
That looks great. If it was an API project, there is no way
that you can add one line and the endpoint will be added
there. But here it is pretty simple. Similar to map get, we
have my foot and pap delete. So I agree if the app not map here,
and we scroll down, we have to delete. We have bad POST, PUT.
And where is the get right here. So you can see we have all of
those basic methods of the API endpoint. With that in place,
let me continue from the next video. Right now we are adding
or returning what we have in a single line. But what if you
have a complex calculation that your API needs to handle and
unique multiple lines for that, that is simple as well, we will
remove this and we will add a curly bracket here. We can
perform all the calculations right here. But to keep things
simple, we will just return as a word right now. Perfect. This
will work exactly the same. Let me run that. And show that.
Write that out. Perfect. That looks good. Now right now you
can see it returns 200. Okay, that is the response that we are
getting from the server. But let's say there are some errors
here. And we are returning an exception here. But that time
also it will return a 200. Okay, right now there is no way to
tell that, hey, this is a bad request or something went wrong
on the server. So basically, we have no way of controlling what
is the return type for our API. Alright, now, that is also done
everything that we want to return inside results dot end we
have the endpoints for the status code. We have accepted,
created, not found, bad request and all of that right here.
Let's say we have a bad request here. And inside there, we are
seeing that there is some exceptions that is being thrown.
Let me run that. Way. We'll try this here. And
perfect. Now you can see our API is returning a 400, which stands
for parrot request. If everything was good, right here,
we can directly return results dot Okay, inside there, we will
pass the hello world. If we want to keep that in same line. If
you want multiple lines, you can add the curly brackets and do
the same thing with results start. Okay. Let me run this and
make sure that works. We have enclosed here examined the
response that is 200. Okay, so perfect. With that, let's
continue from the next video. That returned results here we
can toggle on whether it is a good request or a bad request.
But in an API endpoint, sometimes we have to pass
something to the parameters. That might be a front body, or
let's say an integer or a string parameter. to parse some data.
When we have to use an integer, typically, in an API, we have to
write the integer name here, let that be an ID. That stays the
same. But right here, we will see that we are expecting an
integer ID. And we don't want exception, we will save okay
here. And we can print the ID. And we'll just say plus here,
let me run that. Perfect. You can see it expects an ID,
Swagger UI is displaying that. Let me enter 11 and execute.
Perfect, we have the correct response. If you enter a string
here, swagger will display the error message. It has to be an
integer, but we can open postman here, paste that URL, and see
what happens. We see the exception here failed to bind
the parameter integer ID from this. And you can see the
response type is 400. Bad request. But if we are passing a
string, then this should actually be a 404 not found.
Because the get endpoint that we have is the endpoint with an
integer and not a string. How do we fix that? Fixing that is
super simple. Let me go back to the map get here. If we go back
here, and we explicitly say that this ID will be an integer only,
that should solve our problem. Let me go back to the postman.
And let me execute. And perfect. This time, we have the 404 not
found. And that looks good. So we can be explicit with the
parameters similar to what we had in the API project as well.
We have seen some basic examples of adding the endpoints. But let
me work on something that is close to a real world
application. Let's say we want to perform CRUD operations on a
model and that will be coupons. So, first, we need to create a
model for that inside solution, we will create a new folder and
that will be models in there we will right click add a class
file, I will call that as coupon and inside there I will create
six properties, we will have idea of the coupon we will have
the coupon name, what percentage discount will that coupon give
and if that coupon is active or not, I will also add another
level created and last updated. Now if you are new to dotnet
six, and if we examined the project here at a project file,
you can see in a label is enabled by default. This
basically means that if something is not you have to
explicitly define that property will be now but to make things
simple or if you are working with a legacy dotnet application
or dotnet core project that is an older version, this must be
disabled, even if you upgrade that because many times
personally I have seen when I have upgraded Get the project to
latest versions of dotnet core. And if this nullable is enabled,
API endpoints are breaking, because previously, we did not
explicitly define every endpoint that it is an allowable
endpoint. But now if that is not defined, it does not find that
endpoint. So to be safe, you can disable the nullable in the CS
proj file. But right here, we have explicitly said that
created and last updated is nullable. So we should be good.
But to avoid any issues or confusion, we have disabled in
the level flag inside the project file. So our class here
looks good. Next, we need to create a store that will have a
list of coupon. Now down the road are typically in a real
world project, you don't have a store, you have a database where
you manage or update all the coupons. But to keep things
simple, for now, we will add a coupon store. Let me create a
new folder, which will be data folder. And in there, we will
add a class, which will be coupons store. Inside there, we
will add a static property, which will be coupon list that
will be released off coupon and we have just added two coupons
in there. We will make this a static class as well.
Thankfully, we do not have to create object every time.
Perfect. So our coupons total can now be accessed with our new
API endpoints that we will create in the next video. Now
that we have coupons store and coupon model, it is time to add
the first endpoint that will retrieve all the coupon. So we
will say tap that map get endpoint and the route here.
Rather than calling it coupon. I typically like to add API in
front of that. So we will say forward slash API, and then
coupon that will retrieve all the coupons. We will be using
the delegate here. And what he will return is results dot okay.
And inside there, we have to access the coupons store that we
created. I will add the USING statement. And in there we have
the coupons list. That is what we need to return. With that in
place. Let me run the project. Perfect. Let me try this out
here. And great. We can see both the coupons in our coupons
store. Now right now, even though we have one line here,
let me add a curly bracket here and break this out. Right here,
we will add a return statement. And we are missing the closing
semicolon. Perfect. We have the multi line function right here.
Great. So our cat endpoint looks good. Let me continue from the
next video. We have the endpoint to get all the coupons. But what
about when we have to retrieve an individual coupons based on
the ID, we can create that as well. We know how to retrieve
the ID. So right here, we will expect an ID and that will be
integer, we will have the same name here integer ID. And then
when we are returning back the result here from the coupon
last, we can use first or default to retrieve the record
based on the ID. So if you.id is equal equal to the ID, perfect,
let me run the project. We have ID one and Id two. Let me try
the ID two here. And great, we get the 20 off. So our coupons
store is working as expected, we have to ID and that retrieval is
working. Next what we want is post PUT and DELETE action
endpoints. So let me just add them for now. We need the post
here to create a coupon and when we post we will use the same
path API forward slash coupon. Now of course when we post in
the handler here we will receive a different object but we will
worry about that later on. Okay, let me copy this and paste it
two more times here lightmap post we have my put here and we
have the map delete. Now in post and put both of them we will
receive the coupon object and the parameters that pay we can
create yet are added the coupon, but when we delete here, we will
receive ID. So let me copy that. And we will get the ID right
here. Perfect. So these three looks good. In the next video,
let me first work on creating a coupon. Now we want to create a coupon.
When we create a coupon, we typically receive a coupon
object from the party. So getting that is exactly same
like we do in API project, we will save from party in the
parameter here, and we will receive a coupon object, let me
call that coupon. And we will add USING statement for our
model. Now from body requires a USING statement which is in
Microsoft dot ASP NET Core dot MVC. But once we add that it
will know that a coupon object will be passed from body when
the post request will be called. Then before we create, we
typically have some validation, we will add a validation here
that if the coupon ID is not zero, or if the coupon name is
empty, that is an invalid ID or coupon name, because when we are
creating the coupon ID must be zero. If it is something else,
then that is not a valid ID. Because ID is something that
typically the database, all the code is responsible for adding.
But we don't have any database right now. So now we need to
populate the ID. How will we do that? We will keep things
manual, we will say coupons.id is equal to inside our coupons
store, we have the last third, let me order by descending, so
we will get the maximum ID at the top here, you close to a
u.id. And on there, we will retrieve the first record, they
have to will retrieve the ID of that record. So here we are
getting the maximum ID of all the records that we have in our
coupon store. So that will be two right here. On that too, we
will add one. That means that we are manually setting the id plus
one by the maximum ID in our coupon store. And before I add
the ID here, I want one more validation, I do not want the
same coupon to be created again. So we can add an if condition in
our coupon store and try to retrieve first or default, based
on the name that is being created in the coupon. I will
use that to lowercase that we will make coupon case
insensitive. So if the code already exist, we return part
result. Coupon name already exist. Pretty good. Next, we
have the ID here. And then we have to add it to our coupon
store dot coupon List dot add we will be adding coupon perfect
our create or post is complete here. Once we do that, we can
return back with those dot okay. And there we can return the
coupon that has been created. Perfect. Let me run and see this
in action. Only parameter that we have to change here is name
let me call that 30 off. And it is a 30% discount ID we can
leave that as zero because if we go back to our application, we
are changing that Id based on the ID that we have in our
coupons store. The maximum one is two. So next one will have
the ID of three the ID here we can remove that and it will
still work because it will automatically populate the ID.
Let me remove that and hit the Execute button will scroll down
and perfect in the response body you can see it is three. If we
go back and we try to get all here. Now we have three coupons.
But again, this is a temporary data store. When you restart the
application, there are coupons stored will be back to the first
two which are the defaults that we have. So keep that in mind.
We are not storing this in database. It is temporary and in
memory. So perfect. Our post is working as expected. Let me
continue from the next video. Before I work on put or delete
when we have the post Here, there are quite a few things
that are missing in our API endpoint that we typically do in
a dotnet. core API. One thing is rather than returning an okay,
in HTTP POST, sometimes we return the created at route.
Now, of course, we can return the created. And that is
completely okay. Before that, let me show you how to use the
results dot created. When we use created, we have to write the
route where this is created. And then for the value, we can pass
coupon. So the URL here, let me use string interpolation here.
It's API forward slash coupon, and then we need the ID. ID will
be inside coupon.id. And let me run that we will create a new
coupon, we will update the name and percent. And let's go down
that is created. Here we have two one. And in the location, we
have API coupon and three. Let me go to the local host URL
here, we will add local how localhost and then we will paste
the route that we copied, and grade that retrieves the
appropriate coupon with the correct name, and percent. So
created is working as expected. But what if we want to use the
created add route? For that, we actually have to give this cat
some route name. How to do that with minimal API. After the map
CAC, here, we have something called as with name. And then we
can provide name of this endpoint. So right here, I can
call this endpoint as get coupon. And then we can use that
name. The first one here, let me contact s cat coupons, the HTTP
POST, we will call that as create coupon 10 Rather than
using created, let me copy this commented out. And we will be
using created at route. Inside there, we need the route name as
the first parameter. That is character coupons. Next
parameter here is the ID. So we will create a new object. And we
will say ID is equal to coupon.id. And finally, we will
pass the object that looks good. Let me see if that works. We
will post again, it will create an ID three. Let me try that.
And perfect. That looks good here in the location, we have
the complete URL, as well as the endpoint. If you copy that, and
cry that it should work. Perfect. So with that, we know
how to use the width name to give our endpoints a name. And
then we can use that in something like created at round. Now we have the names for our
endpoint. But if I run the project here, and if I look at
the swagger documentation for HTTP post here, the response
type here, it says that it will only return a 200. Okay. But
that is not correct. If we go back here, if the ID is not
zero, let me try that here. So we will keep it as three execute
this, we get a 400. So basically, our endpoint can
return a 400 bad request. But in the Available responses in the
Swagger UI, it only thinks that it will return a 200. Okay. And
that is because in a traditional API application, we have the
HTTP response. And we explicitly say that these are the possible
status code that our endpoint can return. How can we define
that with minimal API for that on the map post here, where we
have the with name, we also have something called as producers.
And here we have generic when we can see the model that will be
produced. We know we are creating a coupon here. So I can
say produces a coupon and then what will be the status code. If
everything is successful, that will be 211. We also have a bad
request here. The way the ad produces and when it is a bad
request. We do not have any model so we will just add a
produces 400 bad request If you have other status code, you can
also add them right here. Let me copy this, and we will modify
our individual kit and get out. Now this one will produce a 200.
Okay, it does not produce bad request. So let me remove that.
And to Hungary, the first one here will not be a coupon, it
will be an IEnumerable of coupon. Perfect. Let me restart
the application. Right here you can see we have an array, when
we have the individual GATT, we do not have the square bracket.
But let me open the post here. And there we have 201, we have
the correct model, and 400 bad request, we do not have any
model in that. So that way, we can explicitly define what will
be the response that will be produced. On top of that, you
can be explicit on what this endpoint will accept. Right here
it is expecting a coupon. So when we have the with name, we
can also a dot accepts that expects a coupon. And there you
can explicitly write the content type. Like if you want to limit
application JSON, you can see that explicitly right here. With
that, let me run the project. Once again. We go to post here,
and everything stays the same because we have the request
party. But that is more documented. Can now the swagger
can read, what are the exact things that it expects, what it
produces, and the models as well. So perfect. With that our
three endpoints that we have, I believe we have good
documentation so far. Let me continue from the next video.
When you work with a dotnet core application, Dependency
injection is a very critical piece. And minimal API supports
that. So don't panic. The first example that we will see is the
built in ilogger, that comes with an API project. To see that
in action, let me create an API project because I removed the
one that we have here, we will create a sample. That's okay, we
don't care about anything else here. And perfect. Here. If we
open our controller, you will notice we have an ilogger on
there we can use to log something in the console window.
This ilogger is being used with dependency injection, and it is
available by default. So how can we use that in our minimal API
project? Let me log something when we are getting all the
coupons right here. In the parameter here, we can
explicitly say that we need an ilogger. So if I go back to the
API project, let me copy what we were passing in the constructor
here, we do not need to create a private read only, we can
directly retrieve that in parameter like that, you can see
ilogger is being detected, but it does not detect the weather
forecast controller. But right now, we are in program class
here. So we can see that right here. And with that the logger
has been injected, I like to use underscore for all the
dependency injection that we have. We will add underscore
logger. On that we have the lock method, log level, we will say
information. And we will say getting all coupons. Let me run
the application and see if that works. We are using Kestrel to
run the application. So when you run the project, you will
actually have a command line window like this that is open.
Make sure to open that if you do not have that and if you're
using IIS express to run that you can also go to the output
window and we have debug here. Let me pin that as well.
Perfect. Now, if I go back here, let me try to get the coupons.
We execute that and perfect. You can see in the logs here and go
to places in the console window if that is open, if not we have
the output window here we have the log which is getting all
coupons. So that way you can see how Dependency injection is
already built in with minimal API's. If you are injecting
something that is not available, you will of course have to
inject that where we have If the add services right here, and it
will basically be before line 14, where you are calling the
builder dot build. So where we have the builder dot services,
you can register new services, and in the endpoint, you can
directly get the implementation. So with that basic example of
dependency injection, let's continue from the next video.
Now, let me run the project here. And I want to show you
when we are posting here, we do not want all of these
properties, we only want name present and is active. So in a
typical API, we do not expose the complete object, we only
expose the DTOs for that endpoint. So for create, we will
add a DTO in our project. In Models folder, let me add a new
folder for DTO. And in there, I will add a new class, which will
be coupon create ETL. Now that I only want three properties, so
let me copy them and paste those right here, we will go to our
endpoint here. And when we are creating from body, we will only
retrieve the coupon creativity that we are only getting what we
want. And I will call this coupon underscore C underscore
DTO, which has coupon create DTO. Let me change the names
here. We need the ID as well. Now in
our coupon create DTO, we do not have the ID, we can remove this
condition. But when we have to assign the ID, we actually have
to convert this coupon create DTO to coupon DTO. So if you
want, you can manually do that coupon is equal to new. And we
can do the manual mapping like that. Once we do that, we can
add ID on this coupon add that to our coupon store and we are
returning back the coupon. Now rather than coupon here, let me
add a new T to that we will call that as coupon TTL. The reason
behind that is let's say we never want to show when the
coupon was last updated. So in the coupon DTO we will not have
that property and we will return back the coupon DTO so produces
here will be a coupon DTL except we will change that to coupon
create DTO and when we return back, we will basically have to
convert this coupon to the coupon dt. So right here, we
will need the conversion again like that. And perfect. That
looks good. We will return back the coupon DTO let me run the
project and see that in action. We go to our post here perfect.
Now this is different, we only need a few properties here. Let
me change those and we execute. We take a look at the response.
Perfect updated is not present. And that looks good. Now created
is null you can change that if you want but I will skip that
for now. Basically, our details are functional. And we are not
exposing our entity, which is coupon that is great news. But
having all this conversion is super ugly. I would love if
someone would already do that for me. And the answer for that
in next video. Mapping all of the objects manually is super
painful. Thankfully there is auto mapper so far that we will
have to install the new kit package. Let me go there. In the
Browse tab, we will search for auto mapper we will have to
install the default auto mapper package, then we want to inject
auto mapper with dependency injection. So we will install
auto mapper dot extensions dot Microsoft dot dependency
injection perfect both of them are installed. Now how can we
define the mapping auto mapper is smart. If the property names
are seen here, it automatically maps them but we need to tell
auto mapper that hey, you should be mapping coupon to coupon
create DTO or coupon DTO to coupon that is something that we
have to tell Automapper let me add a class file And we will
write that inside that class file. I will call that as
mapping config. Now if you want that configuration, you can do
that in program.cs, when we register that to the container,
but rather than keeping everything clustered in
program.cs, I like to separate it out. Now that mapping is
present inside the profile that is inside auto mapper. Once we
add that here on the class file, in the constructor, we can call
the default methods, that is create map that create map is
inside the profile. And there we have to tell the source and
destination, we want to map our coupon at a USING statement. And
we want to map that to coupons create TTL. Now, that will only
map coupon to coupon create DTO. But what if you want to map
coupon create DTL two coupons, that is simple, we just have
rewards method. And that will handle both the scenario I will
copy this next I also want coupon to coupon DTM. We will
not be mapping coupon creativity to Groupon TTL. So that mapping
is not needed. While these two mapping liquor. Now we need to
inject Automapper to dependency injection. And that we will have
to do before we build the application. So right here, I
will say builder dot services dot add auto mapper. And then we
will explicitly say type of mapping config mapping config
has all the profiles for our auto mapper that we need. And
with that, it will do all the magic of dependency injection.
And we can use that right here in our post endpoint. If you
remember, when we have to inject the logger here, we were using
our logger. Similarly, we want the eye mapper, let me call that
underscore mapper. And we need to add the USING statement for
auto mapper that will automatically inject the mapper
based on the mapping profile that we have. When we have to
convert something we will say coupon is equal to and
underscore mapper dot map, we want to map this to a coupon.
And here we will say we want to map this coupon create DTO. And
this will be the destination. So it will automatically map this
coupon create DTO to coupon and assign it right here. One line
to replace all the mapping. Pretty simple. Let me go back.
And here we will say underscore mapper dot map. What is the
destination address coupon DTO. Let's add that. And what is
something that we are converting are the source here. That is
coupon object. Nothing else is needed. Perfect. That looks
good. With that, let me run the project and make sure it still
works. We were trying to create something here. And great, that
is still functional. And everything is working as
expected. If you have worked with the API's with dotnet, you
know that where we have all the models, like right here we have
the coupon create DTO we can add something like required, and we
can add data annotation. Then if we go to program that CVS right
here on the request, we can check if the model state is
valid, then proceed further. But with minimal API's model state
validators are not included by default. Well, at least not for
now. It might be in future, but that is not there in the
roadmap. And the idea is to keep it minimal. So if you require
validation, you can of course add your custom validation. Like
right here we have the bad request and so on. But if you
want to use something else like fluent API, you can also add
that in your API project. In order to add that we will be
adding nougat package. So right here we will search for fluent
validation. We will be installing the fluent validation
dependency injection extension. Perfect, that looks good. And
with that we can add validations rather than clustering
everything by we'll be adding a new folder here. or call that as
validation. And we will be adding individual validation.
Now validations might be different when you're creating
or when you're updating a coupon. So, that means add a
class here, which will be coupons create validation for
fluent validations, we will have the base class of abstract
validator, we will add the USING statement and there it is on
generic. So, we need to define what this class will be
validating and that will be cufon Create DTL we can add a validation and
constructor here. And with fluent validation, we use Rule
four and there we define what is the validation we want. So,
first thing we do not want name to be empty, and the percent it
must be between one and 100 person, Satish great forward,
how can we add that validation inside our endpoint right here?
Well, we need to inject the validator right here similar to
what we did with AI mapper. So, right here, let me add I
validator on coupon create DTO. We will call that as underscore
validation. And before we check for the name here, we will say
variable validation result is equal to acing and on the
underscore validation, we have validate a sync insert there we
have to pass the coupon create DTO now, we have an error here
because this is an async method and we will have to await but
the endpoint that we have here is not a sink. One workaround is
to remove a weight and right here we can call the get awaited
dot get result and that will work that is completely okay.
Let me show that. Once we have the validation result here, we
can check if the validation result.we have the is valid. If
that is not valid, we will return back an error message.
Now error messages are also inside the validation result
here. So we can say validation result dot errors, duck, first
or default. And we can convert that to a string if there are
any errors. So that looks good. Of course, if you want you can
customize that rather than returning first or default, you
can return all the errors, but again, we are keeping things
super simple. For a fact, let me run this and show the error
message. When we run that we see a weird error message failure to
infer one or more parameters. And in the parameter service we
have something called as unknown. Well here it says Did
you mean to register unknown parameter as a service that
basically means the dependency injection that we added for
validation here, we of course forgot to add that to our
container. So to add that, we will say filter dot services dot
add validator from Assembly containing and here the class
that we are in is program class that will register the validator
service and we can use that with dependency injection. If we run
that, everything works and let me try first here are sent we
will make it more than 100 and execute. We scroll down perfect,
we see the error message percent must be between one and 100 you
enter rebel one zero. So our validation is working. But if we
go down here, we are using the get a waiter dot get result. Let
me continue and remove that in the next video. We are using the
get a waiter dot get result. But what if we do not want that we
indeed want to await here and we want to make our endpoint async.
Doing that is no big deal right before the bracket here. We can
write async here and that will make our endpoint an
asynchronous endpoint. So that was a super easy fix there. But
now I have one question for you. We are injecting two things here
i mapper I validator and then this one we are retrieving from
body. If we go up well we have the integer Id even if we don't
define anything here. Let's say if we are saying that I logger
will be present here. And then we have the integer ID FA
fronted you will Notice it works that out and grid that works.
So, how is the application determining on what it is
getting with dependency injection, what it is getting
with parameters, and everything is confusing, because we are not
seeing that this ilogger is actually being injected. What
happens is the application will first see for all the parameters
that hey, is there a dependency injection registered for this
logger or I mapper, if it is, then I will be injecting that
right here. For the other parameters, like ID, it knows
that it is expecting an ID here. But if it is a coupon, create
DTO or something else, and it does not find any dependency for
that, then it knows that that will be provided as parameter. A
does all of those pretty smart mapping automatically. And we do
not have to worry about that. So that is one thing that I wanted
to point out. With that, let's continue from the next video.
Now with the endpoints that we have, like let's say we have
this coupon create DTO. Right here, we are returning back a
coupon DTO. And then when we have get here, we are returning
a coupon per get all we are returning an IEnumerable of
coupon. What I want to do is rather than returning a
different response based on the type, I want just one single
response type. And that will of course have a data. Along with
that it will have other properties, like any error
message, whether the request was successful, what was the status
code, and so on. So that way, all of our endpoint will have a
standard response message. So in solution here in our models, let
me add a new class. And we'll call that API response. In
there, I want few properties. First one will be a Boolean on
if everything was good. So that will be a success. Then we want
an object, which we will call as a result. And anything that our
API or endpoint returns back, like a coupon list, or a single
coupon, or the coupon that was created. All of that will be in
this result object. Next, I want the status code. So that will be
of type HTTP status code. And finally, I want all the error
message. So let's have a string. And we can call that as error
messages. Perfect, that object looks good here in the
constructor, we will check to see error messages is equal to
new list of string. Perfect, looks good. So rather than
returning anything else here, every time we will be returning
the API response. So at the top here, we will have a new API
response. And when we are returning, we need to store the
result in response dot result is equal to we have the coupon
store that coupon last year. And once we retrieve that, we can
see the response that is success is true. And response dot status
code is equal to HTTP status code dot okay. Let me remove
system.net here and add that in a USING statement. Finally, when
we have results, that okay, we can return back the response
that looks good. This way, we are standardizing what will be
the return type that will be API response. Let me copy these four
lines. And we have the MapKit. Here, let me work on that. We
also need the API response, I should have copied that. And the
result here is right here with four star default, we will paste
that. And perfect. That looks good for the get individual
coupon. Then let me copy this again. While we have the post I
will paste it right here. And when we are actually creating we
can just set a success to be false. And the status code to be
HTTP status code dot path request that we were we have the
bad request. We did not have to assign both the flags here.
That'll cut the result here. everything that is good will be
at the end, we will paste it right there. But when something
is not valid, we need to assign the error message. So we can say
response.we have the error messages that add, we will be
adding the error message right here, cut that pasted, looks
good. Again, you can be fancy rather
than first or default, you can return all the error message,
but you will have to do some conversion where we have
resulted that bad request, we will return back the response.
Let me copy these two lines, we will have to add that right
here. And perfect, looks good. Now, here rather than using
fluent validation, sometimes you also need server side
validation. That is why I have added the custom error message
and returned back the response. We go down here where we have
the created at route, we will return just okay here, because
we have a standard response. That response will have the
coupon DTO. So let me add that here. And the status code here.
You can of course, a created if you want. And that looks good.
We do not need this return statement, we will comment and
let me cut and pasted at the end when we have the other created
with that the accepts here looks good. But the producers is API
response to a one looks good. Let me make sure everywhere we
have that it will be API response. Great. We have
modified quite a few things. But now we have streamlined on what
will be the response for all the endpoint, it will only have our
standard API response that you can see. Let me try to get here.
And it's success is true. It returns them status code 200
looks much better. Let me try the post here. We will try an
invalid percent. And perfect, we have the Edit message.
Everything is much more organized with a single type of
API response. Let me try to create and make sure that works.
Make this a valid one. And we scroll down perfect is success.
We have the result that looks good. With that API response.
Let me continue from the next video. Now that we have added
the cat endpoint get all and post, I want you to take an
assignment and implement the put and to delete endpoints. One
thing that you have to be careful is with the port
request. If I go back for create, we have a coupon create
DTO that we don't have an ID. But when you are updating, you
will require the ID that needs to be updated. So for that, you
will have to create a new DTO call that coupon update DTO and
implement all of those endpoints that are missing. We already
added them you just need to implement these two endpoints
right here. So good luck with that assignment. And I will show
you the solution in the next video. I hope you were able to
complete the assignment. First thing we need to create a DTO we
will copy and paste that and this will be coupon update DTL.
The name here one property that I want to add here is the ID
everything else looks good. Perfect. We need to work on my
port here. Let me go to the map post and copy what we have
pasted right here. Route is the same way we'll change that to be
math put here. And we need Automapper validator will be on
coupon update DTO and from body we will receive a coupon update
DTL Perfect. Now that we have validation like me add that as
well. Copy and paste here and we have coupons updated to letter Perfect. Now when we are
updating, we can add one more validation that Id cannot be
empty, and it has to be greater than zero. Perfect validation
looks good. That may go back to where we have the HTTP POST. Let
me copy what we have here. And we will update for a fact copy
that. Let me add some space here. That way, I can easily
read that. I think this is good enough. Delete, leave some
space. Perfect. Let's see what we are doing here. We have the
API response looks good. We are validating let me call this
underscore view for update. Perfect. We are validating the
result here. That looks good. Let me scroll down. We have the
logic for if coupon already exist, we will have to tweak
that when we are updating to make sure we don't get the ID
that we are already updating. But I will skip that for now.
You can add some more validations here if you want.
But I will keep things super simple. After that, in order to
update we need to retrieve that coupon. So basically, we will
retrieve that coupon using first or default based on the ID that
we receive in the coupon underscore you dot DTO. Once
rated crave that then we can manually update all the
properties in this coupon that we retrieved from the coupon
store based on the coupon yield DTO that we receive in
parameter, we do not need any of these larger care. Let me use
auto mapper using auto mapper, we will map that to be coupon
DTO. And we want to convert the coupon from store to coupon de
to assign that to the result, status code here will be okay
and not created. And perfect. That looks good. We also need to
add the accepts here, we can give that a name. So let me copy
this. And right here, I will paste that name, we can call
that as update coupon. It accepts a coupon update DTO and
produces will be 200. Okay, great. Update looks good. Let me
run and test that. If we try to get here, we have one and two.
Let me try to update do right they're not supposed. But try
that I ID if we keep that as zero, we should see our
validation. Perfect ID must not be empty. We will keep that as
two here. Change the name and percent here to be 12. Let me
execute with scroll down for a fact it is successful. Let me
try to get out of here. And great. Our update is working as
expected. We go back and we will update the Delete. I will copy
what I have within the method here. They stayed inside delete,
we only receive the ID here you can add a custom validator for
delete, but we will keep things simple and I will remove the
validations right here. When we are deleting we want to retrieve
that. So we will retrieve that using first or default. And here
we can just check if coupon is not known. Then we will delete
and this will be to one from store. In that case, we will
remove the coupon from coupons store. Else we have an error
here that we can add the error message invalid ID default
successes walls so we can return back the response or five looks
good. If everything is good in the if condition here. We can
return back the success is true. And status code is okay. If you
want you can also return no content. It depends on how you
want to implement. But with Delete. Typically we return no
content. Perfect. Looks good. With that. Let me try delete in
action. We get here we have the default Part One and two. If
required to delete the ID three, we should get an error message
invalid ID. Let me try to here we get 200. Okay, and execute
that. Our store now only has one coupon. So perfect with that,
update and delete functionalities are working as
expected.