How to create your own little Restful Web API without getting get lost in the process — Part 2
I’m back!. After a little talk about Serverless, a trip to Austin to the Azure Developer Tour, and lots of reading about ASP.NET Core 2.x, I finally got the time to finish this little API.
In this post I’ll cover the implementation of the get, post, put, delete methods, the authentication in a web API and seeding some data with Entity Framework Core.
Before jump into the code, I would like to tell you that this example was not so easy to do. I did get lost a bit trying to use Automapper, seeding data with Entity Framework Core and the set up of the Identity provider to use Cookie based authentication. On every subject I searched in the official documentation, stackoverflow posts and blogs from MVP developers. But, there are so many details and differences between all the versions of ASP.NET Core that it was tricky at some parts to get the “right” way to do it. I’m not saying this is the right way to do it. This example is just for “demo purposes”, and on each subject I will let you know its pros and cons of this design.
A small tip if you are a beginner in this subject as I am: always check the official docs, and if you read a blog post check the version they are using on the example is shown. I hope this will save you some valuable time and you won’t get confused with the changes between versions.
Here’s the list of frameworks and versions that I used in this example:
- ASP.NET Core 2.x
- ASP.NET Core Identity 2.2.1
- Automapper 3.2.0
On part 1, we defined the model and some entities that will be used in the demo. What is next is, adding a repository pattern to handle the data layer.
Using repository pattern
This post is not about good practices, but I considered important to mention what are the benefits in this application of using the repository pattern: it will allow to isolate the data layer of the application, ease unit testing, and also will keep out the business logic from the data layer. More details about the repository pattern can be read at https://msdn.microsoft.com/en-us/library/ff649690.aspx.
The usage of this pattern has also some drawbacks; performance is one the most expensive ones. Keep this aspect in mind if you consider this pattern a good option in your API design.
Implementation
Add a new folder at the root of your project, and call it Repository, then add a new interface inside the Repository folder and call it ICrudRepository. This interface will be the bridge between data and operations with the business logic.
Here is the generic code of add, delete and save methods that will be used on some of the end points of the API.
Now add a new class, this one will be the implementation of the ICrudRepository interface. Inside of the repository folder add the CrudRepository class. Once you add the new file add the inheritance from the ICrudRepository interface defined previously. You can use the refactoring options from Visual Studio, where it can generate the signature of the methods that implement the interface. If you want to avoid to type the signatures, locate the cursor on the name of the ICrudRepository and right click on it, then select the context menu with the light bulb and select implement interface.
The implementation of the interface ICrudRepository has some added methods which will be used to query the Book and Category tables, these methods will be called at the methods in the controllers.
Completing the MVC Pattern
The presentation layer of the API needs to have the models that will be used to send the data in json format back and forth between the data layer and the browser from each request. Add a Models folder at the root of the project, then add the following files that will contain each of the models required:
I won’t put all the models up here, please if you want take a look to it at github. I want to emphasize the differences between each model based on what was needed at the controller method, and thus sent to the browser. In some cases I removed the navigation property of the Book entity, like in the case of the BookWithoutCategoryModel class. Depending on what I wanted to send to the json data. This was an experiment for me. Although I’m not sure if this is fine for a bigger application where consistency in the data format, could be needed, across all the end points for an entity, so I will keep this aspect in mind.
Setup mapping profiles
Mapping the data between objects can be a tedious task. Using a library like Automapper makes it a little easier. Add its nuget package, so it can be used in the project to map the models to each entity. I added the 3.2.0 version.
The classes can be at the Models folder, since there is where the definition for the models for each entity is located.
The following code takes care of the mapping between the Book and the BookModel entity. There are a couple of places where you can put this configuration. For example at the startup class of your asp.net core project. I chose this place for simplicity, and it seems cleaner to me.
Mapping between Category and the Category Model entity.
Books and Categories Controllers implementation
Once the models are in place, the controllers are able to use them. Take a look at each Controller in order to see which methods serve each HTTP verb. There are some conventions used: The Route attribute, indicates that the path to access every method would be [api]/[controller] (the name of the controller). This controller implements the get method for querying all the books from the database, get book by id, add, update and delete book, which completes all the CRUD operations.
You can take a look at the category controller also on the github repository where you can also download it from.
Cookie based Authentication with Identity provider
To handle security there are several options in ASP.NET Core. I decided to start from the simplest point, so I could get an understanding of the framework and its configuration options. When using identity you can use Cookie based authentication, which relies on the users and its roles created at the database. For the configuration of the identity options you need to add some things to the Startup class at the ConfigureServices and Configure methods, which I describe bellow:
ConfigureServices method:
- Add the .AddIdentity<user, IdentityRole>() to the services collection. First parameter is the class name that inherits from the class IdentityUser , if you extended it, and the second one the IdentityRole name class.
- Add the .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(config => config.SlidingExpiration = true) to the services collection. This will set up the
AuthenticationScheme
toCookieAuthenticationDefaults.AuthenticationScheme
which provides a value of "Cookies" for the scheme. You can supply any string value that distinguishes the scheme. - Add the configuration of the options for the cookie and also add the configuration for the OnRedirectToLogin event. This is an important configuration since by default the framework will try to get the login page when there is an unauthorized request, that is useful when you are doing an application, but in the case of an API there is no login form, so instead it should be sent an error code of 401.
Notice that this configuration should be added before the AddMvc() method.
Configure method:
- Add at the the app.UseAuthentication(); call.
The image below has all the mentioned changes:
Take a look also to the rest of the services added at this two methods of the startup.cs file.
- AddEntityFrameworkStores<BooksCatalogContext>()
- AddAutoMapper();
- AddRouting(opt => opt.LowercaseUrls = true)
ASP.NET Core adds even more customization options in one place, which is something I really liked about this version of the framework.
To complete the authentication implementation we need also a controller to handle the POST to the login request. Add a new controller and call it AuthController.cs with the following code:
This will add the POST verb with the login end point to be used for the authentication.
At the level of each method in the controllers you can add the [Authorize] attribute at method level or you can do it at the controller level. You need to choose the one that suits better your requirements. In this example I added the Authorize attribute at the Books controller at the Get Books method, just as an example.
There are a lot more things for the authorization part that you can add to customize access to your end points, based on your roles, which I’m not covering in this post.
Seeding data with Entity Framework Core and ASP.NET Core
Seeding data is something that is useful when you need some pre-loaded data by default in your database. In this case, I wanted to have an administrator user. Seeding data in Entity Framework Core was a bit tricky since I did not find a clear example, but here are the steps that I followed:
- Add a new class at the Data folder at the root of your project.
- Make it static and public so you can access it from the Program.main static method.
I added a category and a book data, and a seed method. Since a user to the identity tables needs to be added, I passed the parameters for the user manager, role manager and the BooksCatalogDBContext object. First it checks that the data does not exist already in the database before added it. An administrator user was added along with its role.
The other part of seeding data is calling this method at the Main method of the Program class. I looked for ways where the seeding method was called using EF migrations, but that did not work. This approach is not my favorite since every time the application starts it will check if the data exists. I will look for other alternatives.
Here is the code at the main method:
In order to test the API, you can use any client that you prefer, like Postman or Restlet studio. These are two that I like with a nice user interface. In this case I used Postman.
Here are some screenshots of the results:
There are a lot of details that need to be added to this API. Like HTTPS or add a link in the response for each resource, etc. I will add more things in future posts.
Conclusion
Doing an API with ASP.NET Core was a bit tricky in some parts, since there has been some changes through all the versions of the framework. Although it is a great framework with a lot of flexibility and customization options, that I think makes it a good choice for API implementations.
Next post I will deploy this API to Azure.
I Hope you find this example useful. Please feel free to ask or comment about any aspect of this example. You can find here the github repository of the example.
References:
Thanks for reading!