Is there a better way to serde serialize a struct defined in different crate?

Hello,

I am looking for alternative solutions to this problem... A sample project that shows this issue: https://storage.googleapis.com/abitofhelp_public_share/serdebin.zip

I have a domain crate that contains a Project struct. The domain crate must not include external dependencies, such as serde.

When I wrap the Project inside a struct, ProjectDto, in a different, dependent crate and add serialization tags, the compiler reports that the Serialize trait has not been satisfied for the Project field in the ProjectDto.

Is there a way to make this work without adding the external dependency to the domain crate?

I can only think of copying the project.rs file from the domain crate and pasting it into the crate that needs to do the serialization. I can add serde's tags to it. I can create a mapper that maps between the Projects in both places in case they diverge.

Here is the error that is reported by the compiler:

error[E0277]: the trait bound `Project: Serialize` is not satisfied
    --> src/project_dto.rs:6:39
    |
6   | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
    |                                       ^^^^^^^^^ the trait `Serialize` is not
    |                                                 implemented for `Project`
7   | pub struct ProjectDto {
8   |     pub project: Project,
    |     --- required by a bound introduced by this call

Thank you for your time and interest,
Mike

Have you looked at this page in the docs? Derive for remote crate · Serde

4 Likes

That is one weird take. If you need your type to be serialized, why "must it not" include Serde as a dependency? That would be the proper solution.

2 Likes

This is for a "clean architecture" project. The domain must only contain structs with no external dependencies. In this architecture, there is another layer that adapts requests to models and vice-versa, which requires serde. Anyway, this is the reason for keeping the domain devoid of serde.

This may be a good alternative: Derive for remote crate · Serde

Depending on what your definition of a "clean architecture" is, if you simply want to allow the domain create to be used without serde, but still be able to use serde on the models when needed, you could simply include serde as a feature.

e.g.

#[cfg_attr(feature = "ser", derive(Deserialize, Serialize))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Project {
    pub name: String,
}

Then in your domain Cargo.toml you have

[dependencies]
serde = { version = "1.0", features = ["derive"], optional = true }

[features]
ser = ["serde"]

and in your main crate's Cargo.toml, you have

[dependencies]
domain_lib = { path = "./domain", version = "0.1.0", features = ["ser"] }

Then other crates that want to use the domain crate but not build any of the serde implementation stuff just doesn't include the ser feature when adding it as a dependency and it wont be compiled in at all.

7 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.