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 101 has a quantity of -2, which creates a total of -440.
  • Order 102 sends its own price of 1, so two lattes cost only ₹2.
  • Order 103 does 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, or total.
  • 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 Request when 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:

  1. Why every API request should be validated.
  2. What request and response DTOs are.
  3. How DTOs prevent over-posting.
  4. How to validate requests and return multiple errors.
  5. How data annotations simplify validation in C#.
  6. 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:

  • item
  • quantity

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:

  • price
  • total
  • id

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

SymptomCauseFix
Orders with negative totalsThere is no range check on quantityCheck 1 <= quantity <= 10
Customers set their own priceThe 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 anotherValidation stops at the first errorCollect all errors, and then answer
Internal fields appear in repliesThe full database class is returnedReturn 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 400 with 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.