Crates.io | dto_derive |
lib.rs | dto_derive |
version | 0.1.1 |
source | src |
created_at | 2019-03-19 21:31:46.628835 |
updated_at | 2019-03-20 23:21:02.940744 |
description | Derive for automatic mapping DTOs to Entities and vice versa. |
homepage | |
repository | https://github.com/mb1986/dto_derive |
max_upload_size | |
id | 122538 |
size | 43,432 |
#[derive(Dto)]
This crate 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.
Add the following dependency to Cargo.toml
:
[dependencies]
dto_derive = "0.1.0"
Then import Dto
derive by:
use dto_derive::Dto;
And use it like so:
struct Post {
...
}
#[derive(Dto)]
#[dto(entity = "Post")]
struct PostResponse {
...
}
That enables you to convert Post
into PostResponse
in this case:
let post: Post = ...;
let post_response: PostResponse = post.into();
For more examples and use cases check sections below.
#[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.
Let's start with our Post
entity implementation:
struct Post {
title: String,
body: String,
}
In order to create a new post we may have a DTO representation:
#[derive(Dto)]
#[dto(entity = "Post")]
#[dto(request)]
#[dto(map = "body: content")]
#[dto(skip = "csrf_token")]
struct NewPost {
title: String,
content: String,
csrf_token: String,
}
Above DTO may be converted to the Post
entity using into()
function from Into
trait:
let newPost = NewPost {
title: String::from("Awesome post"),
content: String::from("Awesome content of awesome post."),
csrf_token: String::from("abcde"),
};
let post: Post = newPost.into();
It is possible because NewPost
DTO is implementing Into
trait
due to Dto
derive.
Response DTO may look like:
#[derive(Dto)]
#[dto(entity = "Post")]
#[dto(map = "content: body")]
struct PostResponse {
title: String,
content: String,
}
The conversion from entity to PostResponse
DTO may be done using
into()
function from Into
trait:
let post = Post {
title: String::from("Awesome post"),
body: String::from("Awesome content of awesome post."),
};
let postResponse: PostResponse = post.into();
It is possible because PostResponse
DTO is implementing From
trait
due to Dto
derive.
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):
impl Into<Post> for NewPost {
fn into(self) -> Post {
Post {
title: self.title,
body: self.content,
}
}
}
The opposite implementation will be derived for the PostResponse
DTO
which is in fact a response DTO:
impl From<Post> for PostResponse {
fn from(entity: Post) -> Self {
PostResponse {
title: entity.title,
content: entity.body,
}
}
}
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.
Licensed under the MIT license (LICENSE or https://opensource.org/licenses/MIT).