DTO’s: What are they and why are they used?
When researching about the topic of DTOs I came across this answer on stackoverflow, answering what DTOs are and I think it’s pretty straight forward and cohesive
A Data Transfer Object is an object that is used to encapsulate data, and send it from one subsystem of an application to another.
Let’s suppose we have three layers in our application, a service that interacts with a database, an Api that calls the service and returns a response and a graphical interface to present the information.
The service queries the database and brings back information according to a model (class with properties or record) in our application; maybe our model has some properties we don’t want to expose to the user like a social security number or an id. So when the Api gets the results from the service we can use a DTO to map the data we need and return it to the client (GUI).
Example of a simple application
In this application we have a Service with some Models that are classes with properties based on database tables. These models may contain sensitive information like the example above.
public class Person
{
public Guid Id { get; set; }
public string Name { get; set; }
public string LastName { get; set; }
public long SocialSecurityNumber { get; set; } //Obviously we wouldn't store social security numbers like this but go along with it for example sake.
}
Our Service is going to return a list of people or a specific person, when it returns this information it’s going to contain the sensitive property that we do not want to expose, in this case the social security number.
Since I didn't want to plug in the project to a database I'm using the class constructor to add information to a list of people for this example.
public class PeopleInformationService
{
private List<Person> peopleList = new List<Person>();
public PeopleInformationService() => peopleList.Add(new Person
{
Id = Guid.NewGuid(),
LastName = "Rivera",
Name = "Genesis",
SocialSecurityNumber = 444-444-444
});
public async Task<List<Person>> GetPeopleList()
{
return peopleList;
}
public async Task<Person> GetPerson()
{
return peopleList.First();
}
}
Now our Api, when it calls the Service and uses the information return will return that data mapped to a DTO which will not be exposing the sensitive properties.
The DTO:
public class PersonDTO
{
public string Name { get; set; }
public string LastName { get; set; }
}
Now we can see in our Api controller that we injected the PeopleInformationService and use the methods created in it.
[Route("api/[controller]")]
[ApiController]
public class PeopleController : ControllerBase
{
private readonly PeopleInformationService peopleService;
public PeopleController(PeopleInformationService service)
{
peopleService = service;
}
[Route("getperson")]
public async Task<PersonDTO> GetPerson()
{
var person = await peopleService.GetPerson();
return new PersonDTO
{
LastName = person.LastName,
Name = person.Name
};
}
[Route("getpeople")]
public async Task<List<PersonDTO>> GetPeople()
{
var personList = await peopleService.GetPeopleList();
var mappedPersonList = new List<PersonDTO>();
foreach(var person in personList)
{
mappedPersonList.Add(new PersonDTO
{
LastName = person.LastName,
Name = person.Name
});
}
return mappedPersonList;
}
}
Now if we use our newly created endpoints we’ll see the response contains the DTO objects with the defined fields.
Takeaways:
- DTOs help us with security since we only return information for the necessary fields.
- They also might help with performance because instead of returning all the data in a table we can just bring back what we specifically need.