Request Validation and DTOs
By the Syncfusion DevTutorials team · Last updated
Stop bad data at the door: use request and response DTOs, block over-posting, validate every field, and return every error as a validation problem.
Validation means checking incoming data before the API accepts and uses it. A DTO (Data Transfer Object) is a simple class or type that defines exactly what data is allowed to enter or leave the API. It acts as a filter between the client and the server.
Together, DTOs and validation help protect the API from incorrect, missing, or unwanted data. Instead of trusting everything the client sends, the API checks the data first and accepts only what follows the rules.
Watch Bad Data Get Saved
The API accepts and saves everything that the client sends. Press Run. The Requests box sends three orders that should never be accepted by a real application.
Program.cs — the API saves anything
- Order
101has a quantity of-2, which creates a total of-440. - Order
102sends its own price of1, so two lattes cost only ₹2. - Order
103does not even include an item name.
All three orders receive 201 Created.
In simple words: the API trusted the client completely. This is dangerous because anyone can send any JSON they want. In this lesson, you will learn how to check requests before accepting them and allow only the fields and values that are valid.
TL;DR
- Never trust the client. Anyone can send requests directly to your API.
- A request DTO defines what data a client is allowed to send.
- A response DTO defines what data a client is allowed to receive.
- Never allow clients to set server-owned values such as
id,price, ortotal. - Accepting fields that should not be accepted is called over-posting.
- Validate required fields, ranges, and allowed values.
- Return all validation errors together instead of stopping at the first error.
- Return
400 Bad Requestwhen validation fails. - In C#, attributes such as
[Required]and[Range]can define validation rules directly on the DTO.
A Real-World Example
Think about filling out a form at a bank. The form only contains fields that customers are allowed to complete, such as:
- Name
- Account number
- Amount
There is no field for information that only the bank controls. Before accepting the form, the bank employee checks it to make sure:
- Required details are provided.
- Numbers are valid.
- The information follows all rules.
If something is wrong, the employee points out every problem before processing the form. A request DTO is like that form, and validation is like that review process.
The request DTO allows only approved input. The response DTO controls what information is returned. The complete Order object stays inside the server.
What You Will Learn
In this lesson, you will learn:
- Why every API request should be validated.
- What request and response DTOs are.
- How DTOs prevent over-posting.
- How to validate requests and return multiple errors.
- How data annotations simplify validation in C#.
- How to test an API using invalid input.
Request and Response DTOs
The first step is controlling the shape of the data. The server uses its own internal Order model. The client only sends a small request DTO such as: CreateOrderRequest
which contains:
itemquantity
The server calculates everything else itself. The response is returned through a separate DTO such as: OrderResponse
which only contains the information that the client needs.
Program.cs — request and response DTOs
The client can no longer control fields such as:
pricetotalid
Even if those values are sent, the request DTO ignores them because they are not part of the allowed input. The server now decides all prices and calculates all totals itself.
In C#, a DTO can be as simple as record CreateOrderRequest(string Item, int Quantity);. A record is a concise way to create a class that only stores data. In TypeScript, DTOs are commonly defined using type or interface.
Validate Every Field
A DTO controls which fields can be sent. Validation controls what values those fields may contain.
Every request passes through validation. Invalid requests return 400 with a list of errors, and no data is saved.
Program.cs — validate every field
The first request contains two problems:
- Invalid item name
- Invalid quantity
The response reports both issues. The second request is missing the item name. The third request is valid and receives 201 Created. Returning all errors together helps users fix everything in a single attempt.
Collect all errors before you answer. If you stop at the first one, the customer fixes it, sends again, and only then hears about the second. That is slow and annoying.
Rules on the DTO: Data Annotations
Writing many if statements works, but it becomes difficult to manage as applications grow. In C#, validation rules can be placed directly on DTO properties using data annotations.
Examples include:
[Required]
[StringLength(40, MinimumLength = 2)]
[EmailAddress]
[Range(13, 120)]
These attributes describe the validation rules directly in the DTO.
Program.cs — rules as data annotations
In this example:
- The first request breaks three validation rules.
- The response includes all three validation errors.
- The second request passes validation successfully.
In TypeScript, the same validation rules are often implemented using libraries such as Zod.
Test with Bad Data
A good way to verify validation is to intentionally send invalid data. This example sends several bad requests and then checks what was saved.
Program.cs — throw bad data at the API
All five requests receive 400 Bad Request. One request even attempts to send SQL code as part of the item name.
The final request returns: []
No invalid order was saved. This proves that the validation rules are working correctly.
Validate on the server, always. Checks in the app are nice for the customer, but anyone can skip them by calling the API directly. Only the server's checks protect your data.
Where You See This
- Registration forms show field-specific validation messages.
- Payment systems reject invalid or negative amounts before processing.
- Order systems validate quantities before creating orders.
- ASP.NET Core controllers automatically validate data annotations when using
[ApiController].
Common mistakes
| Symptom | Cause | Fix |
|---|---|---|
| Orders with negative totals | There is no range check on quantity | Check 1 <= quantity <= 10 |
| Customers set their own price | The request type has a price field (over-posting) | Remove it from the request DTO, and look the price up |
| Users fix one error, and then see another | Validation stops at the first error | Collect all errors, and then answer |
| Internal fields appear in replies | The full database class is returned | Return a response DTO |
Exercises
What to Remember
- Never trust the client. Check every request on the server.
- A request DTO lists what may come in. A response DTO lists what may go out.
- The server works out prices, totals and ids. Never accept them from the client.
- Return
400with every error, named by field. - Attack your own API with bad data, to prove that the checks work.
Next: Building a CRUD API. You will put it all together: create, read, update and delete menu items and orders.