locked
Web API Controller How to test for error and return them correctly RRS feed

  • Question

  • User-1274246664 posted

    The following is an example of a web api controller as the current example stands I and wondering what the best practices should be to do the following handle errors of bad data that is passed in and returning notification back to the requester? Looking at best practice are there other noticeable omissions that would be helpful in following best practices?

    [Route("api/Animals")]
    public class AnimalController : Controller
    {
       const string DBConnectionString = "data source=(local);integrated security=true";
    
        public AnimalController()
        {
        }
    
        [HttpPost]
        public IActionResult GetAnimalByName([FromBody]string param)
        {
            var db = new DbConnection(DBConnectionString);
            List<Animal> animalList = db.Animal.Where(e => e.AnimalName.Contains(param)).ToList();
    
            return Ok(animalList);
        }
    
        [HttpPost]
        public IActionResult PostNewAnimal([FromBody]Animal newAnimal)
        {
            if (newAnimal == null || newAnimal.AnimalName == null)
            {
                return BadRequest("New animal model must be supplied");
            }
    
            var db = new DbConnection(DBConnectionString);
    
            bool duplicateFound = db.Animal.Where(e => e.AnimalName == newAnimal.AnimalName).Any();
            if(duplicateFound)
            {
                return BadRequest("Animal name already exist");
            }
            else
            {
                db.Animal.Add(newAnimal);
            }
            return Ok();
        }
    }
    Sunday, July 8, 2018 6:56 AM

Answers

All replies

  • Sunday, July 8, 2018 7:46 AM
  • User-369506445 posted

    Hi

    You can use validation.

    Validation is a very crucial part of Web API implementation

    Please refer to belew link

    https://www.c-sharpcorner.com/article/learn-about-web-api-validation/

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, July 8, 2018 6:41 PM
  • User-1274246664 posted

    Thank you for you answer  my question is would the code the way it is structured work now?

    Sunday, July 8, 2018 7:16 PM
  • User-1171043462 posted

    Yes your Code will work. And you can add additional security using the references I gave

    Sunday, July 8, 2018 7:23 PM
  • User-369506445 posted

    Yes.your code is correct . But validation is more flexible

    Sunday, July 8, 2018 7:28 PM
  • User-1274246664 posted

    Thank you very much for your help,

    So here is a learning opportunity for me.  Looking at the code what do you see that might be a concern and should be addressed?

    Sunday, July 8, 2018 7:31 PM
  • User-369506445 posted

    Things to consider when implementing Web API

    • Validate everything
      Each and every request should validate before processing it whether an Action method is GET, POST, PUT or DELETE.

    • Don't assume about the data you’re receiving
      The data should always be assumed to be bad, until it’s been through some kind of validation process.

    • Validation as a future-proof quality check
      Validated data is more likely to be future-proof for your Web API functionality.

    • Clean code is Important.

    Validation techniques

    The ways given below help you to validate the data for Web API:

    1. Model Validation

    Model in MVC is basically a representation of our data structure. If you validate this data initially, then everything is good for processing. Web API has Model Binding and Model Validation support. The techniques given below will be used for the validation.

    • Data annotation 
      Is a technique, which can be applied on a model class for an ASP.NET Web API Application to validate the data and handle validation errors. It provides a pretty easy way to enable property-level validation logic within your Model layer. ASP.NET MVC 2 includes support for DataAnnotation attributes. Microsoft published a great article on this.
    • IValidatableObject interface
      Data annotation enables us to do properly level validation. How about class level validation?
      How to do class-level validation methods on model objects for some custom rules? The answer is IValidatableObject interface. IValidatableObject interface to implement custom validation rules on a Product model class. ASP.NET MVC 3 included support for IValidatableObject interface.
    Sunday, July 8, 2018 7:40 PM
  • User-369506445 posted

    If you’re exposing a Web API, one of the most basic things you should be doing on every request, and especially on those requests that mutate your system’s state, is ensuring that the data you’re accepting is valid. ASP.NET Core MVC (and Web API 2 and MVC 5, too!) supports model validation as part of the model binding process. You’re likely familiar with it and have seen it used in combination with data annotations like [Required] on model types. (Pro Tip: You don’t need [Required] on value types like int and DateTime – these are inherently required as long as their not marked as nullable via int? or DateTime?). Model validation occurs automatically, but it’s up to you to check its IsValid property and act accordingly. If you don’t, you risk working with an invalid model, which can result in bad data or even security vulnerabilities. Assuming you’re writing an API (not returning a View), the most appropriate response when you encounter bad model state is to return a BadRequest with details about why the data wasn’t valid. You can do so like this:

    if (!ModelState.IsValid)
    {
      return BadRequest(ModelState);
    }

    Unfortunately, this gets pretty verbose when you need to add it to literally every action method in every controller in your API. It violates the DRY principle. You should also strive to avoid conditional logic in your action methods, keeping them small and as simple as possible. In my MSDN article on ASP.NET Core Filters, I talk about how you can use filters to enforce policies in your Web API, making their behavior more consistent and less likely to have bugs. One simple way to do this is with the addition of a ValidateModelAttributethat can be used to perform this same policy action, but using a filter instead of code inside every action method. You’ll find the source for my implementation of this attribute in my Filters sample on GitHub.

    If you don’t want to create and maintain your own filter, even one as simple as this one, you can instead just add the Ardalis.ValidateModel nuget package. Once you’ve added it, you can apply it to your API controllers on a per-method or per-class basis. I recommend creating a BaseApiController class that includes the attribute, and having all of your API controllers inherit from this base class. For instance:

    [Route("[controller]")]
    [ValidateModel]
    public abstract class BaseApiController : Controller
    {
        // any other common behavior or properties
    }

    With this in place, you’ll ensure that model validation takes place automatically on every action method in your web API.

    Sunday, July 8, 2018 7:44 PM
  • User-1274246664 posted

    Thank you for all the help it has been very good reading up on so many new ideas. One additional question  I was looking at the database connection and though about wrapping it in a using statement for garbage collection and putting a try catch around it.  

    So it would look like  

    [HttpPost]
        public IActionResult PostNewAnimal([FromBody]Animal newAnimal)
        {
            if (newAnimal == null || newAnimal.AnimalName == null)
            {
                return BadRequest("New animal model must be supplied");
            }
            try()
    {
    var db = new DbConnection(DBConnectionString); bool duplicateFound = db.Animal.Where(e => e.AnimalName == newAnimal.AnimalName).Any(); if(duplicateFound) { return BadRequest("Animal name already exist"); } else { db.Animal.Add(newAnimal); } return Ok();
    }
    catch(exception ex)
    {
    return BadRequest("Data Access error "+ ex.Message");
    } }


    Would this be better practices that what code was already there?
    Monday, July 9, 2018 1:20 AM
  • User36583972 posted


    Hi TinyPond,

    One additional question  I was looking at the database connection and though about wrapping it in a using statement for garbage collection and putting a try catch around it.  

    You can try to use the using Statement and use the try catch to catch the connection opening error.

    The C# using statement, SQL, and SqlConnection
    https://stackoverflow.com/questions/3079098/the-c-sharp-using-statement-sql-and-sqlconnection

    Besides, you can start a new thread if you have a new question. Please don't ask several questions in the same thread.

    Best Regards,

    Yong Lu

    Monday, July 9, 2018 5:56 AM