# Model validation & API Design

# Model Validation

ASP.NET has a built-in system for validating whether the data sent in requests fits the model set in the code

Additional requirements can be set with attributes

public class Contact

{

public int Id { get; set; }

[Required]

[MaxLength(50)]

public string Name { get; set; }

[MaxLength(100)]

public string Email { get; set; }

}

# Model Validation (continued)

An object can be validated at any time with TryValidateModel method:

[HttpPost]

public IActionResult Post([FromBody] Contact contact)

{

if (!TryValidateModel(contact))

{

return BadRequest(ModelState);

}

Contacts.Add(contact);

return Created(Request.Path, contact);

}

The attributes set a corresponding error message and information to the ModelState which is sent with the bad request result

![](imgs/6-model-validation-and-designing-apis_0.png)

![](imgs/6-model-validation-and-designing-apis_1.png)

Sometimes you might have custom requirements and the action should, according to the standard, return a bad request if the action does not fit those requirements

For example, the simplest possible way to validate the format of an email is to check whether it contains the '@' symbol and with AddModelError add an error if it does not:

if (!contact.Email.Contains('@'))

{

ModelState.AddModelError("Description", "The email is not in valid form.");

}

Then check the model state:

if (!ModelState.IsValid)

{

return BadRequest(ModelState);

}

# Exercise 1:

Continue working on CourseAPI.

Mark all the properties of the Course class with the [Required] attribute

Create an endpoint for POST requests with the URI api/courses

All the contents of the new course should come from the request body and the new course should be added to the Courses list

The maximum number of credits should be 20 and minimun 1 (Tip: Range)

Return an appropriate response

# Model Validation - Limiting PATCH

* If we only want to allow the PATCH operation to affect Name and Email properties of Contact class
  * Begin by declaring a class with only those fields:
* public class ContactPatch
* {
* public string Name { get; set; }
* public string Email { get; set; }
* }

# Model Validation - Limiting PATCH (continued)

Use the ContactPatch class instead of the actual class for patching:

[HttpPatch("{id}")]

public IActionResult Patch(int id, [FromBody] JsonPatchDocument<ContactPatch> patchDocument)

{

Contact initialContact = _contactRepository.GetContact(id);

ContactPatch patchContact = new ContactPatch

{ Name = initialContact.Name, Email = initialContact.Email };

patchDocument.ApplyTo(patchContact, ModelState);

if (!ModelState.IsValid)

{

return BadRequest();

}

initialContact.Name = patchContact.Name;

initialContact.Email = patchContact.Email;

_contactRepository.UpdateContact(id, initialContact);

return Ok(initialContact);

}

# Designing APIs

It's useful to get a good overview of the API for yourself and others before getting to work

| __Method__ | __Endpoint__ | __Description__ | __Success__ | __Failure__ |
| :-: | :-: | :-: | :-: | :-: |
| __GET__ | __/api/contacts__ | __Return all contacts__ | __200 Ok__ | __400 Bad request__  __404 Not found__ |
| __POST__ | __/api/contacts__ | __Add a new contact__ | __201 Created__ | __400 Bad request__ |
| __PUT__ | __/api/contacts/{id}__ | __Update a contact__ | __204 No content__ | __400 Bad request__  __404 Not found__ |
| __PATCH__ | __/api/contacts/{id}__ | __Partially update a contact__ | __204 No content__ | __400 Bad request__  __404 Not found__ |
| __DELETE__ | __/api/contacts/{id}__ | __Remove a contact__ | __200 OK__ | __404 Not found__ |

