[Awesome Rust] dto_derive : Automating the process of mapping DTOs (Data Transfer Objects)
dto_derive
dto_derive
provides Dto derive automating the process of mapping DTOs (Data Transfer Objects) into Entities and vice versa. It is capable of implementing From
or Into
traits for DTO structures regarding conversion direction.
Every DTO structure can act as a request or a response, which means that particular DTO structure can be converted either from an Entity or into an Entity. Therefore, a DTO which should be convertible into an Entity is a request DTO and a DTO which should be built from an Entity is a response DTO.
In addition to a simple one-to-one conversion, the crate allows skipping particular fields or renaming them during conversion process. More advanced features, like for example, assigning an external values or field-level attributes are planned for next releases.
Installation
Add the following dependency to Cargo.toml
:
1 | # Cargo.toml |
Usages
Then import Dto
derive by:
1 | use dto_derive::Dto; |
And use it like so:
1 | struct Post { |
That enables you to convert Post into PostResponse in this case:
1 | let post: Post = ...; |
For more examples and use cases check sections below.
Derive associated attributes
-
#[dto(entity = "Entity")]
Required attribute containing a type of a mapped
entity
. It has to be provided exactly once per DTO structure. -
#[dto(request)]
,#[dto(response)]
Optional attributes specifying a conversion direction, can be omitted when DTO structure name ends with …Request or …Response, e.g.,
PostResponse
, otherwise have to be provided. -
#[dto(map = "a: b")]
Optional attribute telling how to rename field names during conversion. It may be repeated for different fields.
-
#[dto(skip = "a, b, c")]
Optional attribute containing field names which should be omitted during conversion. It may contain multiple fields to skip and/or it may by repeated for different fields. The attribute is only valid for request DTOs.
Examples
Let’s start with our Post entity implementation:
1 | struct Post { |
Request DTO
In order to create a new post we may have a DTO representation:
1 |
|
Above DTO may be converted to the Post
entity using into()
function from Into
trait:
1 | let newPost = NewPost { |
It is possible because NewPost
DTO is implementing Into
trait due to Dto
derive.
Response DTO
Response DTO may look like:
1 |
|
The conversion from entity to PostResponse
DTO may be done using into()
function from Into
trait:
1 | let post = Post { |
It is possible because PostResponse DTO is implementing From
trait due to Dto
derive.
Under the hood
Adding #[derive(Dto)]
attribute means providing automatic implementation of From
or Into
trait for a given structure.
Thus, for the NewPost
DTO structure and the Post
entity (from previous section), below implementation will be automatically provided (notice the request nature of the NewPost
DTO):
1 | impl Into<Post> for NewPost { |
The opposite implementation will be derived for the PostResponse
DTO which is in fact a response DTO:
1 | impl From<Post> for PostResponse { |
It is worth noting that a derive implementation is always provided for DTO structures which allows to import entity structures from another crate without breaking the orphan rule - https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type.
FAQs
Use Post in other module
1 |
error[E0308]: mismatched types
1 |
|
There are two diffrent type for id
attribute between PostResponse
and Post
.
1 | error[E0308]: mismatched types |
error: required request
/response
attribute or struct name ending with Request
/Response
1 | error: required `request`/`response` attribute or struct name ending with `Request`/`Response` |
Remember to append #[dto(request)]
or #[dto(response)]
for the struct which not end with …Request or …Response.
1 | #[derive(Dto)] |
References
[2] dto_derive 0.1.1 - Docs.rs - https://docs.rs/crate/dto_derive/latest
[3] orphan rule - https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type