Home » C# » .Net Core web API – how to handle required fields for create and update

.Net Core web API – how to handle required fields for create and update

By Emily

I’ve been building an ASP net core web API recently using .Net Core, and whilst I built my object model class quite quickly, as I was developing the endpoints for both create (POST) and update (PATCH) I could see a conflict relating to required fields. I wanted to know how to build the model class so that certain properties were required when we create the object, and not required when we update the object. I didn’t want to build two classes, one for create and one for update – it’s never good to duplicate code, and in this particular project the model would end up with a lot of properties, so I needed to find an alternative. In the end the solution we found was so simple, I wanted to share it in case it helps someone else trying to figure out how to fulfill the same requirements.

I won’t go into the details of how to build a .Net core Api, I will presume you already know the fundamentals. This post will just focus on the solution to requiring fields on create that you don’t need during an update.

Building a simple .Net core API

I’ll use a simple class in this example

//a simple model
public class BookModel
{
     public Guid Id { get; set; }
     public string Name { get; set; }
     public string Author { get; set; }
     public string Description { get; set; }
}

Define the endpoints in the Controller class

Then we define the endpoints in the controller class. The ControllerBase class that is inherited provides many properties and methods for handling HTTP requests. You can read more here.

[ApiController]
[Route("[controller]")]
public class BooksController : ControllerBase{

	private readonly ILogger<BooksControlle> _logger;

    public BooksControlle(ILogger<BooksControlle> logger)
         _logger = logger;
    }

    [HttpGet]
    public IEnumerable<Book> GetBooks()
    {
        //...
    }

    [HttpGet("{id}")]
    public Book GetBook(int id)
    {
        //...
    }
	
    [HttpPost]
    public Book CreateBook([FromBody] BookModel data)
    {
        //...
    }

 	[HttpPatch("{id}")]
    public Book UpdateBook(int, id, [FromBody] BookModel data)
    {
        //...
    }
}

Set the required properties for Create and Update

So once you’ve built your basic API, and the endpoints, we now want to ensure that we get the correct validation when the user starts using the API. When the user creates a new book we want to make sure they always provide us with a Title and an Author, so you’d think we could use an attribute property of [Required] to ensure this, and that would work. But then when the user tries to update a Book, if they just want to update the Title, they’ll receive an error message saying they need to provide the Author too. Presuming that this is not the behaviour you want for your API, then the answer could be to create two Models, one for Create (with required properties) and one for Update (with no required properties).

However a better solution would be to create your Model with no Required properties, and then create a second class specifically for Create that inherits from the initial class. In this second class you then override each of the properties that you need to be Required. SO the BookModel class is developed to become this:

public class BookModel
{
     public Guid Id { get; set; }
     public virtual string Name { get; set; }
     public virtual string Author { get; set; }
     public string Description { get; set; }
     public DateTime Published { get; set; }
  
}

And then we add a new class for Create specifically which inherits the class:

using System.ComponentModel.DataAnnotations;

public class BookModelCreate : BookModel
{
     [Required]
     public override string Name { get; set; }
     [Required]
  	 public virtual string Author { get; set; }
}

Each of the properties that we need to be a required field when we create a new Book is added to this class using override, and we add the [Required] annotation. And this gets the exact behaviour we want in our net core Api while keeping easily maintainable code and avoiding duplication.

If you need to set up logging in your code, then read my other post which explains how to set up logging in a .Net Core project and Azure.