The Get Request is something we can’t miss while creating API because it is the most common request. So, it is very important to learn more about handling that kind of request.
In the previous post, we have created a repository pattern for collecting the data from the database.
Now, it is time to use that repository for business logic.
We are going to keep all the database logic inside the repository classes. Controllers will be responsible for handling requests, model validation, and returning responses to the frontend part of the application.
By doing so, our controllers won’t be overwhelmed with the code thus making the code easier to read and maintain as well.
So, let’s start.Controllers and Routing in WEB API
To create a controller, right-click on
the Controllers folder inside the main project and Add/Controller. Then
from the menu choose API Controller - Empty
and name it OwnerController.cs
:
Every web API controller class inherits from the ControllerBase
abstract class that provides all the necessary behavior for the derived class.
Also, above the controller class we can see this part of the code:
This represents the routing and we will talk a little bit about the routing inside Web APIs.
Web API routing routes the incoming HTTP requests to the particular action method inside the Web API controller.
There are two types of routings:
- Convention based routing and
- Attribute routing
Convention-based routing is called that way because it establishes a convention for the URL paths. The first part makes the mapping for the controller name, the second part makes the mapping for the action method, and the third part is used for the optional parameter. We can configure this type of routing in the Startup class in the Configure method:
Attribute routing uses the attributes to map the routes directly to the action methods inside the controller. Usually, we place the base route above the controller class, as you can notice in our Web API controller class. Similarly, for the specific action methods, we create their routes right above them.
GetAllOwners GET Request in .NET Core
Let’s start.
First, let’s change the base route from: [Route("api/[controller]")]
to: [Route("api/owner")]
.
Even though the first route will work just fine, with the second
example we are more specific to show that this routing should point to
the OwnerController
.
Now it is time to create the first action method to return all the owners from the database.
In the IOwnerRepository
interface create a definition for theGetAllOwners
method :
Then implement that interface inside the OwnerRepository
class:
Finally, we need to return all the owners by using the GetAllOwners
method inside the Web API action.
The purpose of the action methods, inside Web API controllers, is not only to return the results. It is the main purpose, but not the only one. You need to pay attention to the status codes of your Web API responses as well. Additionally, you’ll have to decorate your actions with the HTTP attributes which will mark the type of the HTTP request to that action.
You can read more on HTTP and find some HTTP request examples in part 1 of our HTTP series.
Finally, let’s modify the OwnerController
:
Let us explain this code a bit.
First of all, we inject the logger and repository services inside the constructor. Then by decorating the GetAllOwners
action with [HttpGet]
attribute, we are mapping this action to the GET request. Finally, we
use both injected parameters to log the messages and to get the data
from the repository class.
The IActionResult
interface supports using a variety of methods, which return not only the
result but the status codes as well. In this situation, the OK
method returns all the owners and also the status code 200 which stands for OK
. If an exception occurs, we will return the internal server error with the status code 500.
You can read more about status codes by reading The HTTP series – References.
Because there is no route attribute right above the action, the route for the action GetAllOwners
will be api/owner (http://localhost:5000/api/owner
).
Code Permissions and Testing the Result
We would like to point out one more thing inside GetAllOwners
action. Right now, if you look at the repository structure, its classes inherit from the abstract RepositoryBase<T>
class and also from its own interface which then inherits from the IRepositoryBase<T>
interface. With this hierarchy in place, by typing
. you are able to call the custom method from the _repository.Owner
OwnerRepository
class and also all of the methods from the abstract RepositoryBase<T>
class.
If you want to avoid that type of behavior and to allow actions
inside the controller to call only methods from the repository user
classes, all you need to do is to remove IRepositoryBase<T>
inheritance from IOwnerRepository
. Consequently, only repository user classes will be able to call generic methods from RepositoryBase<T>
class. Likewise, action methods communicate only with repository user classes.
It is all up to you, how you want to organize your code and permissions.
To check the result, we are going to use the Postman tool to send requests towards the application.
Also, you can learn more about how to consume web API programmatically using C# by reading A few great ways to consume restful api in c#.
Let’s start the application, start the Postman and create a request:
Excellent, everything is working as planned.
As you can see, we return all the data from the database with this action. Of course, you can add paging to this action and optimize it by returning only the part of the data.
Before we continue, we would like to
show you one more thing. If you look at the model classes, you’ll notice
that all properties have the same name as the columns they are mapped
to. But you can have the property with a different name than the column
it points to, and still to map each other. To achieve that you need to
use attribute [Column]
.
So, let’s do something like that.
We are going to change the property names from AccountId
and OwnerId
to just Id
in the Owner
and Account
classes. Also, we are going to add the [Column]
property which will map the Id
property to the right column in the database:
Now let’s continue.
Using DTO and AutoMapper
DTO or Data Transfer Object serves the purpose to transfer data from the server to the client. That is exactly what are we going to use it for.
If we take a look at the GetAllOwners
action, we can see that we use the model Owner
class to fetch the data from the database (_repository.Owner.GetAllOwners()
returns
a list of Owner objects) and also to return that result to the client.
And that is not a good practice. A much better practice is to have a
model class to fetch the data from the database and to have a DTO class
to return that result to the client. The DTO object could be exactly the
same as the model object but still, it is much better to use DTO
objects because if something changes in the database the model class
must change but that doesn’t mean that the client wants changed results.
Thus the DTO object will not change.
Having that said, let’s create a new folder DataTransferObjects
in the Entities
project and let’s create OwnerDto
class inside:
As you can see, we don’t have the Accounts property, because we don’t want to show that information to the client right now.
Now, all we would have to do is to map a returned list of owners from the database to the list of ownerDto
.
But, doing that manually is a boring job and if we have twenty or even
more properties in our DTO class, it would be time-consuming as well.
Luckily for us, there is a great tool that could help us a lot in the
mapping process. Yes, it is AutoMapper.
Working with AutoMapper
AutoMapper is a library that helps us map different objects. To install it, we have to type this command in the Package Manager Console window:
PM> Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection
After the installation, we have to register it in the Program
class:
builder.Services.AddAutoMapper(typeof(Program));
Now, we have to create a mapping profile class to tell AutoMapper how to execute mapping actions. So, let’s create a new class MappingProfile
in the main project and modify it:
Finally, we can modify the OwnerController
:
We can send the same request from Postman and we are going to get the same result (without accounts), but now, with much better implementation. AutoMapper has great capabilities and you can learn more by reading Getting Started With AutoMapper in ASP.NET Core.
GetOwnerById GET Request in .NET Core
To continue, let’s modify the IOwnerRepository
interface:
Then, let’s implement the interface in the OwnerRepository.cs
:
Finally, let’s change the OwnerController
:
We are going to use the Postman to send valid and invalid requests to check the results:
Invalid request:
Owner Details Request
Let’s continue by creating a logic to return the owner object with its account details.
First, we need to create the AccountDto
class:
Then, we have to modify our OwnerDto class that will help us return the owner with all related accounts to it. If you want you can create an additional DTO class with name OwnerWithAccountsDto, but for the sake of simplicity, we are going to modify the existing DTO class:
Notice the property Accounts
which will bind all the accounts related to the certain owner.
Let’s modify the interface accordingly:
Also, let’s modify the repository class:
We are using the Include
method to include all the accounts related to the current owner.
We have to add a new mapping rule in the MappingProfile class:
Finally, let’s modify the controller:
Result:
We have created these actions that use Repository Pattern logic synchronously but it could be done asynchronously as well. If you want to learn how to do that you can visit Implementing Async Repository in .NET Core. Although we strongly recommend finishing all the parts from this series for an easier understanding of the project’s business logic.
Conclusion
Requests using GET should only retrieve the data from the database, and all the actions inside the OwnerController class are written like that.
By reading this post you’ve learned:
- How to work with a controller class
- What is routing and how to use it
- How to handle GET requests in a web API
- The way to use DTOs while handling requests
Thank you all for reading and I hope you found something useful in it.
No comments:
Post a Comment