When we first start building API’s we make many assumptions about our users. We assume that they would never input bad data. This is very unrealistic.
Have you ever experienced the frustration of filling out a long form at the dentist office? This is the exact same feeling users have but it’s even greater because nobody is watching them!
This is why we must validate data constantly on both the front-end and the back-end.
ModelState
works in tandem with data validation to provide the holy grail; Error Handling.
Things To Know Before Learning Model State
To prevent users from inputting incorrect data, we rely heavily on two things:
- Model Binding with simple types
Model Binding is what turns a HTTP request from a string to useable programming constructs like int
, string
, bool
. Model binding prevents users from passing in incorrect types (ex., passing in a string
when it should be a bool
). Except in very rare cases, ModelState
will not interact with data binding via simple types. BUT it’s important to know because it relates to our next validation technique.
- Model Binding with complex types
The difference between these two method signatures may not be clear at first, but they differ in what type of data is being passed. The method before we only passed in int
and string
. This method we are passing in entire objects!
Behind the scenes [ApiController]
is parsing massive blocks of JSON and turning them into beautiful objects from which we can manipulate.
Model State
While this parsing is occurring, .NET is in the background checking to see whether these objects are correct. This is where ModelState
comes into the picture.
Remember the [ApiController]
annotation? Well, if .NET finds that something is wrong with the giant block of JSON passed it provides, it returns the ModelState
with things that it found like:
- User did not input enough data
- User inputted too much data
- User inputted a bad email
ModelState
is technically just a giant object in the background that is provides us details of what went wrong with each request. Each endpoint method has it’s own and each request produces a new ModelState
object.
You may be asking yourself, “Well, how does it even know?”.
[ApiController]
does provide some error handling and validation out of the box, but it’s up to the developer to handle what should be classified as wrong.
This is what we have data annotation’s in our DTO and models (although having a data annotation in a model is a serious code smell).
Code like [Required]
,[MinLength]
,[MaxLength]
coordinates with our ModelState
to produces these errors and provide us with the necessary feedback for the front-end to consume.
Conclusion
While .NET does provide us with tons of out of the box tools to make our code better, it’s up to you to let ModelState
know what is going wrong.
Happy coding!