Our first DTO#

In this section we will create our first DTO by extending our script to include a DTO that will ensure we don’t expose the user’s email in the response.

app.py#
 1from __future__ import annotations
 2
 3from dataclasses import dataclass
 4
 5from litestar import Litestar, get
 6from litestar.dto import DataclassDTO, DTOConfig
 7
 8
 9@dataclass
10class Person:
11    name: str
12    age: int
13    email: str
14
15
16class ReadDTO(DataclassDTO[Person]):
17    config = DTOConfig(exclude={"email"})
18
19
20@get("/person/{name:str}", return_dto=ReadDTO, sync_to_thread=False)
21def get_person(name: str) -> Person:
22    # Your logic to retrieve the person goes here
23    # For demonstration purposes, a placeholder Person instance is returned
24    return Person(name=name, age=30, email=f"email_of_{name}@example.com")
25
26
27app = Litestar(route_handlers=[get_person])

Here we introduce a new DTO class (ReadDTO) and configure it to exclude the Person.email field. The route handler is also instructed to use the DTO to handle the response.

Lets look at these changes in more detail. Firstly, we add two additional imports.

The DTOConfig class is used to configure DTOs. In this case, we are using it to exclude the email field from the DTO, but there are many other configuration options available and we’ll cover most of them in this tutorial.

The DataclassDTO class is a factory class that specializes in creating DTOs from dataclasses. It is also a Generic class, which means that it accepts a type parameter. When we provide a type parameter to a generic class it makes that class a specialized version of the generic class. In this case, we create a DTO type that specializes in transferring data to and from instances of the Person class (DataclassDTO[Person]).

Note

It is not necessary to subclass DataclassDTO to create a specialized DTO type. For instance, ReadDTO = DataclassDTO[Person] also creates a valid, specialized DTO. However, subclassing DataclassDTO allows us to add the configuration object, as well as specialize the type.

Finally, we instruct the route handler to use the DTO (return_dto=ReadDTO) to transfer data from the handler response.

Lets try it out, again visit http://localhost:8000/person/peter and you should see the following response:

../../_images/simple_exclude.png

That’s better, now we are not exposing the user’s email address!