Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

.NET Core 2.0 With Angular 4 and MySQL, Part 6: POST, PUT, DELETE

DZone's Guide to

.NET Core 2.0 With Angular 4 and MySQL, Part 6: POST, PUT, DELETE

In this post, we are going to create a POST, PUT and DELETE requests and by doing so we are going to complete the server part (.NET Core part) of this series.

· Web Dev Zone ·
Free Resource

Deploy code to production now. Release to users when ready. Learn how to separate code deployment from user-facing feature releases with LaunchDarkly.

In the previous post, we have created a GET request with some code refactoring actions. In this post, we are going to create a POST, PUT and DELETE requests and by doing so we are going to complete the server part (.NET Core part) of this series.

Let's get into it.

If you want to see all the basic instructions and complete navigation for this series, please follow the following link: Introduction page for this tutorial.

For the previous part check out: Part 5 - Creating .NET Core WebApi project - Using repository for the GET requests

The source code is available for download at .NET Core, Angular 4 and MySQL. Part 6 - Source Code

Handling POST Request

Firstly, let's modify the decoration attribute for the action method GetOwnerById in the Owner controller:

[HttpGet("{id}", Name = "OwnerById")]

With this modification, we are setting the name for the action. This name will come in handy in the action method for creating a new owner.

Secondly, let's modify the interface:

public interface IOwnerRepository
{
    IEnumerable<Owner> GetAllOwners();
    Owner GetOwnerById(Guid ownerId);
    OwnerExtended GetOwnerWithDetails(Guid ownerId);
    void CreateOwner(Owner owner);
}

After the interface modification, we are going to implement that interface:

public void CreateOwner(Owner owner)
{
    owner.Id = Guid.NewGuid();
    Create(owner);
    Save();
}

Lastly, let's modify the controller:

[HttpPost]
public IActionResult CreateOwner([FromBody]Owner owner)
{
    try
    {
        if(owner == null)
        {
            _logger.LogError("Owner object sent from client is null.");
            return BadRequest("Owner object is null");
        }

        if(!ModelState.IsValid)
        {
            _logger.LogError("Invalid owner object sent from client.");
            return BadRequest("Invalid model object");
        }

        _repository.Owner.CreateOwner(owner);

        return CreatedAtRoute("OwnerById", new { id = owner.Id}, owner);
    }
    catch (Exception ex)
     {
        _logger.LogError($"Something went wrong inside CreateOwner action: {ex.Message}");
        return StatusCode(500, "Internal server error");
    }
}

Right now is a good time to test this code by sending the POST request by using Postman.

Let's examine the result in the picture below:

Code Explanation

Let's talk a little bit about this code. The interface and the repository parts are pretty clear so we won't talk about that. But the code in the controller contains several things worth mentioning.

The CreateOwner method has its own [HttpPost] decoration attribute, which restricts it to the POST requests. Furthermore, notice the owner parameter which comes from the client. You are not collecting it from the Uri but from the request body. Thus the usage of the [FromBody] attribute. Also, the owner object is a complex type and because of that, you have to use [FromBody].

If you wanted to, you could explicitly mark the action to take this parameter from the Uri by decorating it with the [FromUri] attribute, though I wouldn't recommend that at all due to the security reasons and complexity of the request.

Because the owner parameter comes from the client, it could happen that the client doesn't send that parameter at all. As a result, you would need to validate it against the reference type's default value, which is null. Later in this post, we are going to refactor this line of code.

Further down the code, you can notice this type of validation: ifValidation Attributes. If for some reason validation fails, the ModelState.IsValid will return false as a result, signaling that something is wrong with the model. Otherwise, it will return true which means that values in all the properties are valid [for example, (!ModelState.IsValid)]. If you look at the owner model properties, Name, Address, and DateOfBirth, you will notice that all of them are decorated with the Validation Attributes. If for some reason validation fails, the ModelState.IsValid will return false as a result, signaling that something is wrong with the model. Otherwise, it will return true which means that values in all the properties are valid.

The last thing to mention is this part of the code:

CreatedAtRoute("OwnerById", new { id = owner.Id}, owner);

CreatedAtRoute will return a status code 201, which stands for Created, as explained in our post: The HTTP Reference. Also, it will populate the body of the response with the new owner object as well as the Location attribute within the response header with the address to retrieve that owner. You need to provide the name of the action, where you can retrieve the created entity.

Code Refactoring

Everything is going great so far.

But...

Let's make some refactoring which will help with the null validation of the CreateOwner method. Also, it will help with the validation of the GET actions.

Just one tip: When you refactor your code, always try to do it in such a manner that will allow reusability as much as possible.

Create a new interface inside Entities project:

namespace Entities
{
    public interface IEntity
    {
        Guid Id { get; set; }
    }
}

Then, we can modify the model classes, OwnerOwnerExtended, and Account, to implement that interface. In the same project, we are going to create the folder Extensions and in that folder create a new class IEntityExtensions.

namespace Entities.Extensions
{
    public static class IEntityExtensions
    {

    }
}

After all, that, let's add an extension method for the IEntity type to validate against null value. Because Owner and Account inherit from the IEntity, we can extend any of those types and validate them.

public static class IEntityExtensions
{
    public static bool IsObjectNull(this IEntity entity)
    {
        return entity == null;
    }
}

Now in the CreateOwner action method replace this code:

if(owner == null)

with this:

if(owner.IsObjectNull())

Let's refactor this code a little bit more.

Create another extension method like this:

public static bool IsEmptyObject(this IEntity entity)
{
    return entity.Id.Equals(Guid.Empty);
}

Now let's just change the code in the controller from:

if (owner.OwnerId.Equals(Guid.Empty))

to:

if (owner.IsEmptyObject())

in the GetOwnerWithDetails and GetOwnerById actions.

Handling PUT Request

Excellent.

Let's continue with the PUT request, to update the owner entity.

First, in the Entities project inside the Extensions folder we are going to create the OwnerExtensions class with the following code:

namespace Entities.Extensions
{
    public static class OwnerExtensions
    {
        public static void Map(this Owner dbOwner, Owner owner)
        {
            dbOwner.Name = owner.Name;
            dbOwner.Address = owner.Address;
            dbOwner.DateOfBirth = owner.DateOfBirth;
        }
    }
}

And then, change the interface:

public interface IOwnerRepository
{
    IEnumerable<Owner> GetAllOwners();
    Owner GetOwnerById(Guid ownerId);
    OwnerExtended GetOwnerWithDetails(Guid ownerId);
    void CreateOwner(Owner owner);
    void UpdateOwner(Owner dbOwner, Owner owner);
}

Modify the OwnerRepository.cs:

public void UpdateOwner(Owner dbOwner, Owner owner)
{
    dbOwner.Map(owner);
    Update(dbOwner);
    Save();
}

Finally, alter the OwnerController file:

[HttpPut("{id}")]
public IActionResult UpdateOwner(Guid id, [FromBody]Owner owner)
{
try
{
if (owner.IsObjectNull ())
{
_logger.LogError("Owner object sent from client is null.");
return BadRequest("Owner object is null");
}

if (!ModelState.IsValid)
{
_logger.LogError("Invalid owner object sent from client.");
return BadRequest("Invalid model object");
}

var dbOwner = _repository.Owner.GetOwnerById(id);
if (dbOwner.IsEmptyObject())
{
_logger.LogError($"Owner with id: {id}, hasn't been found in db.");
return NotFound();
}

_repository.Owner.UpdateOwner(dbOwner, owner);

return NoContent();
}
catch (Exception ex)
{
_logger.LogError($"Something went wrong inside UpdateOwner action: {ex.Message}");
return StatusCode(500, "Internal server error");
}
}

As you may have noticed, the action method is decorated with the [HttpPut] attribute. Furthermore, it receives two parameters: id of the entity you want to update and the entity with the updated fields, taken from the request body. The rest of the code is pretty simple. After the validation, you are pulling the owner from the database and executing the update of that owner. Finally, you return NoContent which stands for the status code 204.

Handling DELETE Request

For the Delete request, steps are the following:

Interface:

public interface IOwnerRepository
{
IEnumerable<Owner> GetAllOwners();
Owner GetOwnerById(Guid ownerId);
OwnerExtended GetOwnerWithDetails(Guid ownerId);
void CreateOwner(Owner owner);
void UpdateOwner(Owner dbOwner, Owner owner);
void DeleteOwner(Owner owner);
}

OwnerRepository:

public void DeleteOwner(Owner owner)
{
Delete(owner);
Save();
}

OwnerController:

[HttpDelete("{id}")]
public IActionResult DeleteOwner(Guid id)
{
try
{
var owner = _repository.Owner.GetOwnerById(id);
if(owner.IsEmptyObject())
{
_logger.LogError($"Owner with id: {id}, hasn't been found in db.");
return NotFound();
}

_repository.Owner.DeleteOwner(owner);

return NoContent();
}
catch (Exception ex)
{
_logger.LogError($"Something went wrong inside DeleteOwner action: {ex.Message}");
return StatusCode(500, "Internal server error");
}
}

So, that is it. Send the Delete request from Postman and see the result. Owner object should be deleted from the database.

Conclusion

Now that you know all of this, try to repeat all the actions but for the Account entity. Because nothing beats the practice, doesn't it?

With all this code in place, we have a working web API which covers all features for handling CRUD operations.

By reading this post you've learned:

  • The way to handle POST request.
  • How to handle PUT request.
  • How to write better and more reusable code.
  • And the way to handle DELETE request.

Thank you for reading and I hope you found something useful in it.

When you are ready, continue to the Part 7 which is the part of series where we introduce Angular. I will show you how to create the Angular project and set up your first component.

For any suggestions or questions, don't hesitate to leave the comment in the comment section below.

Deploy code to production now. Release to users when ready. Learn how to separate code deployment from user-facing feature releases with LaunchDarkly.

Topics:
web dev ,.net core ,server requests ,put ,get

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}